/* * Set the tun MTU dynamically. */ void frame_set_mtu_dynamic (struct frame *frame, int mtu, unsigned int flags) { #ifdef ENABLE_DEBUG const int orig_mtu = mtu; const int orig_link_mtu_dynamic = frame->link_mtu_dynamic; #endif ASSERT (mtu >= 0); if (flags & SET_MTU_TUN) mtu += TUN_LINK_DELTA (frame); if (!(flags & SET_MTU_UPPER_BOUND) || mtu < frame->link_mtu_dynamic) { frame->link_mtu_dynamic = constrain_int ( mtu, EXPANDED_SIZE_MIN (frame), EXPANDED_SIZE (frame)); } dmsg (D_MTU_DEBUG, "MTU DYNAMIC mtu=%d, flags=%u, %d -> %d", orig_mtu, flags, orig_link_mtu_dynamic, frame->link_mtu_dynamic); }
void comp_add_to_extra_buffer(struct frame *frame) { /* Leave room for compression buffer to expand in worst case scenario where data is totally uncompressible */ frame_add_to_extra_buffer (frame, COMP_EXTRA_BUFFER (EXPANDED_SIZE(frame))); }
void check_send_occ_load_test_dowork (struct context *c) { if (CONNECTION_ESTABLISHED (c)) { const struct mtu_load_test *entry; if (!c->c2.occ_mtu_load_n_tries) msg (M_INFO, "NOTE: Beginning empirical MTU test -- results should be available in 3 to 4 minutes."); entry = &mtu_load_test_sequence[c->c2.occ_mtu_load_n_tries++]; if (entry->op >= 0) { c->c2.occ_op = entry->op; c->c2.occ_mtu_load_size = EXPANDED_SIZE (&c->c2.frame) + entry->delta; } else { msg (M_INFO, "NOTE: failed to empirically measure MTU (requires " PACKAGE_NAME " 1.5 or higher at other end of connection)."); event_timeout_clear (&c->c2.occ_mtu_load_test_interval); c->c2.occ_mtu_load_n_tries = 0; } } }
static void lzo_decompress(struct buffer *buf, struct buffer work, struct compress_context *compctx, const struct frame *frame) { lzo_uint zlen = EXPANDED_SIZE(frame); int err; uint8_t c; /* flag indicating whether or not our peer compressed */ if (buf->len <= 0) { return; } ASSERT(buf_init(&work, FRAME_HEADROOM(frame))); c = *BPTR(buf); ASSERT(buf_advance(buf, 1)); if (c == LZO_COMPRESS_BYTE) /* packet was compressed */ { ASSERT(buf_safe(&work, zlen)); err = LZO_DECOMPRESS(BPTR(buf), BLEN(buf), BPTR(&work), &zlen, compctx->wu.lzo.wmem); if (err != LZO_E_OK) { dmsg(D_COMP_ERRORS, "LZO decompression error: %d", err); buf->len = 0; return; } ASSERT(buf_safe(&work, zlen)); work.len = zlen; dmsg(D_COMP, "LZO decompress %d -> %d", buf->len, work.len); compctx->pre_decompress += buf->len; compctx->post_decompress += work.len; *buf = work; } else if (c == NO_COMPRESS_BYTE) /* packet was not compressed */ { } else { dmsg(D_COMP_ERRORS, "Bad LZO decompression header byte: %d", c); buf->len = 0; } }
static void lz4v2_decompress(struct buffer *buf, struct buffer work, struct compress_context *compctx, const struct frame *frame) { size_t zlen_max = EXPANDED_SIZE(frame); uint8_t c; /* flag indicating whether or not our peer compressed */ if (buf->len <= 0) { return; } ASSERT(buf_init(&work, FRAME_HEADROOM(frame))); /* do unframing/swap (assumes buf->len > 0) */ uint8_t *head = BPTR(buf); c = *head; /* Not compressed */ if (c != COMP_ALGV2_INDICATOR_BYTE) { return; } /* Packet to short to make sense */ if (buf->len <= 1) { buf->len = 0; return; } c = head[1]; if (c == COMP_ALGV2_LZ4_BYTE) /* packet was compressed */ { buf_advance(buf,2); do_lz4_decompress(zlen_max, &work, buf, compctx); } else if (c == COMP_ALGV2_UNCOMPRESSED_BYTE) { buf_advance(buf,2); } else { dmsg(D_COMP_ERRORS, "Bad LZ4v2 decompression header byte: %d", c); buf->len = 0; } }
static void lz4_decompress(struct buffer *buf, struct buffer work, struct compress_context *compctx, const struct frame *frame) { size_t zlen_max = EXPANDED_SIZE(frame); uint8_t c; /* flag indicating whether or not our peer compressed */ if (buf->len <= 0) { return; } ASSERT(buf_init(&work, FRAME_HEADROOM(frame))); /* do unframing/swap (assumes buf->len > 0) */ { uint8_t *head = BPTR(buf); c = *head; --buf->len; *head = *BEND(buf); } if (c == LZ4_COMPRESS_BYTE) /* packet was compressed */ { do_lz4_decompress(zlen_max, &work, buf, compctx); } else if (c == NO_COMPRESS_BYTE_SWAP) /* packet was not compressed */ { } else { dmsg(D_COMP_ERRORS, "Bad LZ4 decompression header byte: %d", c); buf->len = 0; } }
void process_outgoing_link (struct context *c) { struct gc_arena gc = gc_new (); perf_push (PERF_PROC_OUT_LINK); if (c->c2.to_link.len > 0 && c->c2.to_link.len <= EXPANDED_SIZE (&c->c2.frame)) { /* * Setup for call to send/sendto which will send * packet to remote over the TCP/UDP port. */ int size = 0; ASSERT (link_socket_actual_defined (c->c2.to_link_addr)); #ifdef ENABLE_DEBUG /* In gremlin-test mode, we may choose to drop this packet */ if (!c->options.gremlin || ask_gremlin (c->options.gremlin)) #endif { /* * Let the traffic shaper know how many bytes * we wrote. */ #ifdef ENABLE_FEATURE_SHAPER if (c->options.shaper) shaper_wrote_bytes (&c->c2.shaper, BLEN (&c->c2.to_link) + datagram_overhead (c->options.ce.proto)); #endif /* * Let the pinger know that we sent a packet. */ if (c->options.ping_send_timeout) event_timeout_reset (&c->c2.ping_send_interval); #if PASSTOS_CAPABILITY /* Set TOS */ link_socket_set_tos (c->c2.link_socket); #endif /* Log packet send */ #ifdef LOG_RW if (c->c2.log_rw) fprintf (stderr, "W"); #endif msg (D_LINK_RW, "%s WRITE [%d] to %s: %s", proto2ascii (c->c2.link_socket->info.proto, true), BLEN (&c->c2.to_link), print_link_socket_actual (c->c2.to_link_addr, &gc), PROTO_DUMP (&c->c2.to_link, &gc)); /* Packet send complexified by possible Socks5 usage */ { struct link_socket_actual *to_addr = c->c2.to_link_addr; #ifdef ENABLE_SOCKS int size_delta = 0; #endif #ifdef ENABLE_SOCKS /* If Socks5 over UDP, prepend header */ socks_preprocess_outgoing_link (c, &to_addr, &size_delta); #endif /* Send packet */ size = link_socket_write (c->c2.link_socket, &c->c2.to_link, to_addr); #ifdef ENABLE_SOCKS /* Undo effect of prepend */ link_socket_write_post_size_adjust (&size, size_delta, &c->c2.to_link); #endif } if (size > 0) { c->c2.max_send_size_local = max_int (size, c->c2.max_send_size_local); c->c2.link_write_bytes += size; link_write_bytes_global += size; #ifdef ENABLE_MEMSTATS if (mmap_stats) mmap_stats->link_write_bytes = link_write_bytes_global; #endif #ifdef ENABLE_MANAGEMENT if (management) { management_bytes_out (management, size); #ifdef MANAGEMENT_DEF_AUTH management_bytes_server (management, &c->c2.link_read_bytes, &c->c2.link_write_bytes, &c->c2.mda_context); #endif } #endif } } /* Check return status */ check_status (size, "write", c->c2.link_socket, NULL); if (size > 0) { /* Did we write a different size packet than we intended? */ if (size != BLEN (&c->c2.to_link)) msg (D_LINK_ERRORS, "TCP/UDP packet was truncated/expanded on write to %s (tried=%d,actual=%d)", print_link_socket_actual (c->c2.to_link_addr, &gc), BLEN (&c->c2.to_link), size); } /* if not a ping/control message, indicate activity regarding --inactive parameter */ if (c->c2.buf.len > 0 ) register_activity (c, size); } else { if (c->c2.to_link.len > 0) msg (D_LINK_ERRORS, "TCP/UDP packet too large on write to %s (tried=%d,max=%d)", print_link_socket_actual (c->c2.to_link_addr, &gc), c->c2.to_link.len, EXPANDED_SIZE (&c->c2.frame)); } buf_reset (&c->c2.to_link); perf_pop (); gc_free (&gc); }
void check_send_occ_msg_dowork (struct context *c) { bool doit = false; c->c2.buf = c->c2.buffers->aux_buf; ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM (&c->c2.frame))); ASSERT (buf_safe (&c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame))); ASSERT (buf_write (&c->c2.buf, occ_magic, OCC_STRING_SIZE)); switch (c->c2.occ_op) { case OCC_REQUEST: if (!buf_write_u8 (&c->c2.buf, OCC_REQUEST)) break; dmsg (D_PACKET_CONTENT, "SENT OCC_REQUEST"); doit = true; break; case OCC_REPLY: if (!c->c2.options_string_local) break; if (!buf_write_u8 (&c->c2.buf, OCC_REPLY)) break; if (!buf_write (&c->c2.buf, c->c2.options_string_local, strlen (c->c2.options_string_local) + 1)) break; dmsg (D_PACKET_CONTENT, "SENT OCC_REPLY"); doit = true; break; case OCC_MTU_REQUEST: if (!buf_write_u8 (&c->c2.buf, OCC_MTU_REQUEST)) break; dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_REQUEST"); doit = true; break; case OCC_MTU_REPLY: if (!buf_write_u8 (&c->c2.buf, OCC_MTU_REPLY)) break; if (!buf_write_u16 (&c->c2.buf, c->c2.max_recv_size_local)) break; if (!buf_write_u16 (&c->c2.buf, c->c2.max_send_size_local)) break; dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_REPLY"); doit = true; break; case OCC_MTU_LOAD_REQUEST: if (!buf_write_u8 (&c->c2.buf, OCC_MTU_LOAD_REQUEST)) break; if (!buf_write_u16 (&c->c2.buf, c->c2.occ_mtu_load_size)) break; dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_LOAD_REQUEST"); doit = true; break; case OCC_MTU_LOAD: { int need_to_add; if (!buf_write_u8 (&c->c2.buf, OCC_MTU_LOAD)) break; need_to_add = min_int (c->c2.occ_mtu_load_size, EXPANDED_SIZE (&c->c2.frame)) - OCC_STRING_SIZE - sizeof (uint8_t) - EXTRA_FRAME (&c->c2.frame); while (need_to_add > 0) { /* * Fill the load test packet with pseudo-random bytes. */ if (!buf_write_u8 (&c->c2.buf, get_random () & 0xFF)) break; --need_to_add; } dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_LOAD min_int(%d-%d-%d-%d,%d) size=%d", c->c2.occ_mtu_load_size, OCC_STRING_SIZE, (int) sizeof (uint8_t), EXTRA_FRAME (&c->c2.frame), MAX_RW_SIZE_TUN (&c->c2.frame), BLEN (&c->c2.buf)); doit = true; } break; case OCC_EXIT: if (!buf_write_u8 (&c->c2.buf, OCC_EXIT)) break; dmsg (D_PACKET_CONTENT, "SENT OCC_EXIT"); doit = true; break; } if (doit) { /* * We will treat the packet like any other outgoing packet, * compress, encrypt, sign, etc. */ encrypt_sign (c, true); } c->c2.occ_op = -1; }