pkt.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /*
  2. * pkt.c
  3. * ptunnel is licensed under the BSD license:
  4. *
  5. * Copyright (c) 2004-2011, Daniel Stoedle <daniels@cs.uit.no>,
  6. * Yellow Lemon Software. All rights reserved.
  7. *
  8. * Copyright (c) 2017-2019, Toni Uhlig <matzeton@googlemail.com>
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * - Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. *
  16. * - Redistributions in binary form must reproduce the above copyright notice,
  17. * this list of conditions and the following disclaimer in the documentation
  18. * and/or other materials provided with the distribution.
  19. *
  20. * - Neither the name of the Yellow Lemon Software nor the names of its
  21. * contributors may be used to endorse or promote products derived from this
  22. * software without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  25. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  28. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  29. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  30. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  31. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  32. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  33. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  34. * POSSIBILITY OF SUCH DAMAGE.
  35. *
  36. * Contacting the author:
  37. * You can get in touch with me, Daniel Stødle (that's the Norwegian letter oe,
  38. * in case your text editor didn't realize), here: <daniels@cs.uit.no>
  39. *
  40. * The official ptunnel website is here:
  41. * <http://www.cs.uit.no/~daniels/PingTunnel/>
  42. *
  43. * Note that the source code is best viewed with tabs set to 4 spaces.
  44. */
  45. #ifndef WIN32
  46. #include <netinet/in.h>
  47. #include <arpa/inet.h>
  48. #include <pthread.h>
  49. #endif
  50. #include <sys/time.h>
  51. #include "ptunnel.h"
  52. #include "pkt.h"
  53. #include "pdesc.h"
  54. #include "options.h"
  55. #include "utils.h"
  56. static proxy_desc_t * handle_incoming_tunnel_request(unsigned bytes,
  57. struct sockaddr_in * addr,
  58. int icmp_sock,
  59. icmp_echo_packet_t * const pkt,
  60. ping_tunnel_pkt_t * const pt_pkt)
  61. {
  62. struct timeval tt;
  63. struct in_addr in_addr;
  64. uint32_t init_state;
  65. proxy_desc_t * cur;
  66. pt_log(kLog_info, "Incoming tunnel request from %s.\n", inet_ntoa(*(struct in_addr *)&addr->sin_addr));
  67. gettimeofday(&tt, 0);
  68. if (tt.tv_sec < seq_expiry_tbl[pt_pkt->id_no]) {
  69. pt_log(kLog_verbose, "Dropping request: ID was recently in use.\n");
  70. return NULL;
  71. }
  72. in_addr.s_addr = pt_pkt->dst_ip;
  73. pt_log(kLog_info,
  74. "Starting new session to %s:%d with ID %d\n",
  75. inet_ntoa(in_addr),
  76. ntohl(pt_pkt->dst_port),
  77. pt_pkt->id_no);
  78. if ((opts.restrict_dst_ip && opts.given_dst_ip && opts.given_dst_ip != pt_pkt->dst_ip) ||
  79. (opts.restrict_dst_port && (uint32_t)-1 != opts.given_dst_port &&
  80. opts.given_dst_port != ntohl(pt_pkt->dst_port))) {
  81. pt_log(kLog_info, "Destination administratively prohibited!\n");
  82. return NULL;
  83. }
  84. if (opts.password) {
  85. init_state = kProto_authenticate;
  86. } else {
  87. init_state = kProto_data;
  88. }
  89. cur = (proxy_desc_t *)create_and_insert_proxy_desc(
  90. pt_pkt->id_no, pkt->identifier, 0, addr, pt_pkt->dst_ip, ntohl(pt_pkt->dst_port), init_state, kProxy_flag);
  91. if (!cur) {
  92. /* if failed, abort. Logging is done in create_insert_proxy_desc */
  93. pt_log(kLog_error, "Failed to create proxy descriptor!\n");
  94. return NULL;
  95. }
  96. if (pt_pkt->data_len > 0) {
  97. handle_data(pkt, bytes, cur);
  98. }
  99. if (init_state == kProto_authenticate) {
  100. pt_log(kLog_debug, "Sending authentication challenge..\n");
  101. /* Send challenge */
  102. cur->challenge = generate_challenge();
  103. memcpy(cur->buf, cur->challenge, sizeof(challenge_t));
  104. queue_packet(icmp_sock, cur, cur->buf, sizeof(challenge_t), 0, 0, kProto_authenticate | cur->type_flag);
  105. }
  106. return cur;
  107. }
  108. static void handle_auth_request(unsigned bytes,
  109. int icmp_sock,
  110. icmp_echo_packet_t * const pkt,
  111. proxy_desc_t * const cur,
  112. challenge_t * const challenge)
  113. {
  114. if (!opts.password) {
  115. pt_log(kLog_error,
  116. "This proxy requires a password! "
  117. "Please supply one usin g the -x switch.\n");
  118. send_termination_msg(cur, icmp_sock);
  119. cur->should_remove = 1;
  120. return;
  121. }
  122. #ifdef ENABLE_SHA512
  123. if (opts.force_sha512) {
  124. pt_log(kLog_debug, "Got authentication challenge - sending SHA512 response\n");
  125. generate_response_sha512(&challenge->plain, &challenge->digest);
  126. } else
  127. #endif
  128. {
  129. pt_log(kLog_debug, "Got authentication challenge - sending MD5 response\n");
  130. generate_response_md5(&challenge->plain, &challenge->digest);
  131. }
  132. memcpy(cur->buf, challenge, sizeof(challenge_t));
  133. queue_packet(icmp_sock, cur, cur->buf, sizeof(challenge_t), 0, 0, kProto_authenticate | cur->type_flag);
  134. /* We have authenticated locally.
  135. * It's up to the proxy now if it accepts our response or not..
  136. */
  137. cur->authenticated = 1;
  138. handle_data(pkt, bytes, cur);
  139. }
  140. static void handle_auth_response(unsigned bytes,
  141. int icmp_sock,
  142. icmp_echo_packet_t * const pkt,
  143. proxy_desc_t * const cur,
  144. challenge_t * const challenge)
  145. {
  146. pt_log(kLog_debug,
  147. "Received remote %s challenge response.\n",
  148. (challenge->digest.hash_type == HT_SHA512 ? "SHA512" : "MD5"));
  149. if ((!opts.force_sha512 && challenge->digest.hash_type == HT_MD5 &&
  150. validate_challenge_md5(cur->challenge, &challenge->digest)) ||
  151. #ifdef ENABLE_SHA512
  152. (challenge->digest.hash_type == HT_SHA512 && validate_challenge_sha512(cur->challenge, &challenge->digest)) ||
  153. #endif
  154. cur->authenticated) {
  155. pt_log(kLog_verbose, "Remote end authenticated successfully.\n");
  156. /* Authentication has succeeded, so now we can proceed
  157. * to handle incoming TCP data.
  158. */
  159. cur->authenticated = 1;
  160. cur->state = kProto_data;
  161. /* Insert the packet into the receive ring, to avoid
  162. * confusing the reliab ility mechanism.
  163. */
  164. handle_data(pkt, bytes, cur);
  165. } else {
  166. pt_log(kLog_info, "Remote end failed authentication.\n");
  167. send_termination_msg(cur, icmp_sock);
  168. cur->should_remove = 1;
  169. }
  170. }
  171. static void header_byteorder_ntoh(icmp_echo_packet_t * const icmp_pkt, ping_tunnel_pkt_t * const pt_pkt)
  172. {
  173. pt_pkt->state = ntohl(pt_pkt->state);
  174. icmp_pkt->identifier = ntohs(icmp_pkt->identifier);
  175. icmp_pkt->seq = ntohs(icmp_pkt->seq);
  176. pt_pkt->id_no = ntohs(pt_pkt->id_no);
  177. pt_pkt->seq_no = ntohs(pt_pkt->seq_no);
  178. }
  179. static proxy_desc_t * get_proxy_descriptor(uint16_t id_no)
  180. {
  181. proxy_desc_t * cur;
  182. /* Find the relevant connection, if it exists */
  183. pthread_mutex_lock(&chain_lock);
  184. for (cur = chain; cur; cur = cur->next) {
  185. if (cur->id_no == id_no) {
  186. break;
  187. }
  188. }
  189. pthread_mutex_unlock(&chain_lock);
  190. return cur;
  191. }
  192. /* handle_proxy_packet:
  193. * Processes incoming ICMP packets for the proxy. The packet can come either from the
  194. * packet capture lib, or from the actual socket or both.
  195. * Input: A buffer pointing at the start of an IP header, the buffer length and the proxy
  196. * descriptor chain.
  197. */
  198. void handle_packet(char * buf, unsigned bytes, int is_pcap, struct sockaddr_in * addr, int icmp_sock)
  199. {
  200. ip_packet_t * ip_pkt;
  201. icmp_echo_packet_t * pkt;
  202. ping_tunnel_pkt_t * pt_pkt;
  203. proxy_desc_t * cur;
  204. uint32_t type_flag, pkt_flag, proxy_flag;
  205. challenge_t * challenge;
  206. proxy_flag = kProxy_flag;
  207. if (bytes < sizeof(icmp_echo_packet_t) + sizeof(ping_tunnel_pkt_t)) {
  208. pt_log(kLog_verbose,
  209. "Skipping this packet - too short. "
  210. "Expect: %lu+%lu = %lu ; Got: %u\n",
  211. sizeof(icmp_echo_packet_t),
  212. sizeof(ping_tunnel_pkt_t),
  213. sizeof(icmp_echo_packet_t) + sizeof(ping_tunnel_pkt_t),
  214. bytes);
  215. return;
  216. }
  217. if (opts.udp || opts.unprivileged) {
  218. ip_pkt = 0;
  219. pkt = (icmp_echo_packet_t *)buf;
  220. pt_pkt = (ping_tunnel_pkt_t *)pkt->data;
  221. } else {
  222. ip_pkt = (ip_packet_t *)buf;
  223. pkt = (icmp_echo_packet_t *)ip_pkt->data;
  224. pt_pkt = (ping_tunnel_pkt_t *)pkt->data;
  225. }
  226. if (ntohl(pt_pkt->magic) != opts.magic) {
  227. pt_log(kLog_verbose, "Ignored incoming packet. Magic value 0x%X mismatch.\n", ntohl(pt_pkt->magic));
  228. return;
  229. }
  230. header_byteorder_ntoh(pkt, pt_pkt);
  231. cur = get_proxy_descriptor(pt_pkt->id_no);
  232. /* Handle the packet if it comes from "the other end." This is a bit tricky
  233. * to get right, since we receive both our own and the other end's packets.
  234. * Basically, a proxy will accept any packet from a user, regardless if it
  235. * has a valid connection or not. A user will only accept the packet if there
  236. * exists a connection to handle it.
  237. */
  238. if (cur) {
  239. type_flag = cur->type_flag;
  240. if (type_flag == (uint32_t)kProxy_flag) {
  241. cur->icmp_id = pkt->identifier;
  242. cur->ping_seq = pkt->seq;
  243. }
  244. if (!is_pcap)
  245. cur->xfer.icmp_in++;
  246. } else {
  247. type_flag = kProxy_flag;
  248. }
  249. pkt_flag = pt_pkt->state & kFlag_mask;
  250. pt_pkt->state &= ~kFlag_mask;
  251. if (pt_pkt->state > (kNum_proto_types - 1)) {
  252. pt_log(kLog_error, "Dropping packet with invalid state.\n");
  253. return;
  254. }
  255. pt_log(kLog_sendrecv,
  256. "Recv: %4d [%4d] bytes "
  257. "[id = 0x%04X] [seq = %d] "
  258. "[seq_no = %d] [type = %s] "
  259. "[ack = %d] [icmp = %d] "
  260. "[user = %s] [pcap = %d]\n",
  261. bytes,
  262. ntohl(pt_pkt->data_len),
  263. pkt->identifier,
  264. ntohs(pkt->seq),
  265. pt_pkt->seq_no,
  266. state_name[pt_pkt->state & (~kFlag_mask)],
  267. ntohl(pt_pkt->ack),
  268. pkt->type,
  269. (pkt_flag == kUser_flag ? "yes" : "no"),
  270. is_pcap);
  271. /* This test essentially verifies that the packet comes from someone who isn't us. */
  272. if ((pkt_flag == kUser_flag && type_flag == proxy_flag) || (pkt_flag == proxy_flag && type_flag == kUser_flag)) {
  273. pt_pkt->data_len = ntohl(pt_pkt->data_len);
  274. pt_pkt->ack = ntohl(pt_pkt->ack);
  275. if (pt_pkt->state == kProxy_start) {
  276. if (!cur && type_flag == proxy_flag) {
  277. cur = handle_incoming_tunnel_request(bytes, addr, icmp_sock, pkt, pt_pkt);
  278. if (!cur) {
  279. return;
  280. }
  281. } else if (type_flag == kUser_flag) {
  282. pt_log(kLog_error, "Dropping proxy session request - we are not a proxy!\n");
  283. return;
  284. } else {
  285. pt_log(kLog_error,
  286. "Dropping duplicate proxy session request "
  287. "with ID %d and seq %d.\n",
  288. pt_pkt->id_no,
  289. pt_pkt->seq_no);
  290. }
  291. } else if (cur && pt_pkt->state == kProto_authenticate) {
  292. /* Sanity check packet length, and make sure it matches what we expect */
  293. if (pt_pkt->data_len != sizeof(challenge_t)) {
  294. pt_log(kLog_error,
  295. "Received challenge packet, but data length "
  296. "is not as expected.\n");
  297. pt_log(kLog_debug, "Data length: %u Expected: %lu\n", pt_pkt->data_len, sizeof(challenge_t));
  298. cur->should_remove = 1;
  299. return;
  300. }
  301. /* Prevent packet data from being forwarded over TCP! */
  302. pt_pkt->data_len = 0;
  303. challenge = (challenge_t *)pt_pkt->data;
  304. /* If client: Compute response to challenge */
  305. if (type_flag == kUser_flag) {
  306. /* Required for integration tests w/ passwd set. */
  307. pt_log(kLog_debug, "AUTH-REQUEST: Received ack-series starting at seq %d\n", pt_pkt->seq_no);
  308. handle_auth_request(bytes, icmp_sock, pkt, cur, challenge);
  309. return;
  310. }
  311. /* If proxy: Handle client's response to challenge */
  312. else if (type_flag == proxy_flag) {
  313. cur->next_remote_seq++;
  314. handle_auth_response(bytes, icmp_sock, pkt, cur, challenge);
  315. return;
  316. }
  317. }
  318. /* Handle close-messages for connections we know about */
  319. if (cur && pt_pkt->state == kProto_close) {
  320. pt_log(kLog_info, "Received session close from remote peer.\n");
  321. cur->should_remove = 1;
  322. return;
  323. }
  324. /* The proxy will ignore any other packets from the client
  325. * until it has been authenticated. The packet resend mechanism
  326. * insures that this isn't problematic.
  327. */
  328. if (type_flag == proxy_flag && opts.password && cur && !cur->authenticated) {
  329. pt_log(kLog_debug,
  330. "Ignoring packet with seq-no %d "
  331. "- not authenticated yet.\n",
  332. pt_pkt->seq_no);
  333. return;
  334. }
  335. if (cur && cur->sock) {
  336. double now = time_as_double();
  337. if (pt_pkt->state != kProto_ack) {
  338. cur->last_data_activity = now;
  339. }
  340. if (pt_pkt->state == kProto_data || pt_pkt->state == kProxy_start || pt_pkt->state == kProto_ack) {
  341. if (pt_pkt->state == kProxy_start) {
  342. pt_pkt->data_len = 0;
  343. }
  344. handle_data(pkt, bytes, cur);
  345. }
  346. handle_ack(pt_pkt->ack, cur);
  347. cur->last_activity = now;
  348. }
  349. }
  350. }
  351. static void queue_payload_data(ping_tunnel_pkt_t * const pt_pkt, proxy_desc_t * const cur)
  352. {
  353. /* Check if we should add payload data to the queue. */
  354. if (!cur->recv_ring[cur->recv_idx] && pt_pkt->state == kProto_data) {
  355. pt_log(kLog_debug, "Queing data packet: %d\n", pt_pkt->seq_no);
  356. cur->recv_ring[cur->recv_idx] = create_fwd_desc(pt_pkt->seq_no, pt_pkt->data_len, pt_pkt->data);
  357. cur->recv_wait_send++;
  358. cur->recv_idx++;
  359. } else {
  360. pt_log(kLog_debug, "Dup packet for %d ?\n", pt_pkt->seq_no);
  361. }
  362. cur->next_remote_seq++;
  363. if (cur->recv_idx >= cur->window_size) {
  364. cur->recv_idx = 0;
  365. }
  366. /* Check if we have already received some of the next packets. */
  367. while (cur->recv_ring[cur->recv_idx]) {
  368. if (cur->recv_ring[cur->recv_idx]->seq_no == cur->next_remote_seq) {
  369. cur->next_remote_seq++;
  370. cur->recv_idx++;
  371. if (cur->recv_idx >= cur->window_size) {
  372. cur->recv_idx = 0;
  373. }
  374. } else {
  375. break;
  376. }
  377. }
  378. }
  379. static void queue_payload_data_out_of_order(ping_tunnel_pkt_t * const pt_pkt, proxy_desc_t * const cur)
  380. {
  381. int r, s, d, pos;
  382. pos = -1; /* If pos ends up staying -1, packet is discarded. */
  383. r = cur->next_remote_seq;
  384. s = pt_pkt->seq_no;
  385. d = s - r;
  386. if (d < 0) { /* This packet _may_ be old, or seq_no may have wrapped around */
  387. d = (s + 0xFFFF) - r;
  388. if (cur->window_size && d < cur->window_size) {
  389. /* Counter has wrapped, so we should add this packet to the recv ring */
  390. pos = (cur->recv_idx + d) % cur->window_size;
  391. }
  392. } else if (cur->window_size && d < cur->window_size) {
  393. pos = (cur->recv_idx + d) % cur->window_size;
  394. }
  395. if (pos != -1) {
  396. if (!cur->recv_ring[pos]) {
  397. pt_log(kLog_verbose,
  398. "Out of order. Expected: %d Got: %d Inserted: %d "
  399. "(cur = %d)\n",
  400. cur->next_remote_seq,
  401. pt_pkt->seq_no,
  402. pos,
  403. cur->recv_idx);
  404. cur->recv_ring[pos] = create_fwd_desc(pt_pkt->seq_no, pt_pkt->data_len, pt_pkt->data);
  405. cur->recv_wait_send++;
  406. }
  407. } else {
  408. pt_log(kLog_info, "Packet discarded - outside receive window.\n");
  409. }
  410. }
  411. /* handle_data:
  412. * Utility function for handling kProto_data packets, and place the data it contains
  413. * onto the passed-in receive ring.
  414. */
  415. void handle_data(icmp_echo_packet_t * pkt, int total_len, proxy_desc_t * cur)
  416. {
  417. ping_tunnel_pkt_t * pt_pkt = (ping_tunnel_pkt_t *)pkt->data;
  418. int expected_len = sizeof(ip_packet_t) + sizeof(icmp_echo_packet_t) + sizeof(ping_tunnel_pkt_t); /* 20+8+28 */
  419. /* Place packet in the receive ring, in its proper place.
  420. * This works as follows:
  421. * -1. Packet == ack packet? Perform ack, and continue.
  422. * 0. seq_no < next_remote_seq, and absolute difference is bigger than w size => discard
  423. * 1. If seq_no == next_remote_seq, we have no problems; just put it in the ring.
  424. * 2. If seq_no > next_remote_seq + remaining window size, discard packet.
  425. * Send resend request for missing packets.
  426. * 3. Else, put packet in the proper place in the ring
  427. * (don't overwrite if one is already there), but don't increment next_remote_seq_no
  428. * 4. If packed was not discarded, process ack info in packet.
  429. */
  430. expected_len += pt_pkt->data_len;
  431. expected_len += expected_len % 2;
  432. if (opts.udp || opts.unprivileged) {
  433. expected_len -= sizeof(ip_packet_t);
  434. }
  435. if (total_len < expected_len) {
  436. pt_log(kLog_error, "Packet not completely received: %d Should be: %d.\n", total_len, expected_len);
  437. pt_log(kLog_debug, "Data length: %d Total length: %d\n", pt_pkt->data_len, total_len);
  438. /* just ignore that packet */
  439. return;
  440. }
  441. if (pt_pkt->seq_no == cur->next_remote_seq) {
  442. queue_payload_data(pt_pkt, cur);
  443. } else {
  444. queue_payload_data_out_of_order(pt_pkt, cur);
  445. }
  446. }
  447. void handle_ack(uint32_t seq_no, proxy_desc_t * cur)
  448. {
  449. if (cur->send_wait_ack > 0) {
  450. int i, can_ack = 0, count = 0;
  451. i = cur->send_idx - 1;
  452. if (i < 0) {
  453. i = cur->window_size - 1;
  454. }
  455. pt_log(kLog_debug, "Received ack-series starting at seq %d\n", seq_no);
  456. while (count < cur->window_size) {
  457. if (!cur->send_ring[i].pkt) {
  458. break;
  459. }
  460. if (cur->send_ring[i].seq_no == seq_no) {
  461. can_ack = 1;
  462. } else if (!can_ack) {
  463. cur->send_first_ack = i;
  464. }
  465. if (can_ack) {
  466. free(cur->send_ring[i].pkt);
  467. cur->send_ring[i].pkt = 0;
  468. cur->send_ring[i].pkt_len = 0;
  469. cur->send_wait_ack--;
  470. }
  471. i--;
  472. if (i < 0) {
  473. i = cur->window_size - 1;
  474. }
  475. count++;
  476. }
  477. } else {
  478. pt_log(kLog_verbose,
  479. "Dropping superfluous acknowledgement for seq %d "
  480. "(no outstanding packets needing ack.)\n",
  481. seq_no);
  482. }
  483. }