int encode_out(Gzb64* gzb64, unsigned char* buf, const size_t length) { int gzout_size, ret; if( gzb64->encoded_last_chunk ) { gzout_size = evbuffer_get_length(gzb64->encode_gzout_buffer); /* dump everything in */ } else { int contiguous = evbuffer_get_contiguous_space(gzb64->encode_gzout_buffer); gzout_size = contiguous - (contiguous % 3); /* must be mutliple of 3 */ } if(gzout_size > 0) { unsigned char* gzout_buf = evbuffer_pullup(gzb64->encode_gzout_buffer, gzout_size); int bytes_written = BIO_write(gzb64->b64_encoder, gzout_buf, gzout_size); evbuffer_drain(gzb64->encode_gzout_buffer, bytes_written); if(gzb64->encoded_last_chunk) ret = BIO_flush(gzb64->b64_encoder); /* flush if last */ } ret = BIO_read(gzb64->encode_output_buffer, buf, length); /* reset for next stream */ if(gzb64->encoded_last_chunk && 0 == ret) { resetEncoder(gzb64); } return ret; }
static void ss_relay_readcb(struct bufferevent *buffev, void *_arg) { redsocks_client *client = _arg; struct bufferevent * from = buffev; struct bufferevent * to = client->client; size_t input_size = evbuffer_get_contiguous_space(bufferevent_get_input(from)); size_t output_size = evbuffer_get_length(bufferevent_get_output(to)); assert(buffev == client->relay); redsocks_touch_client(client); if (client->state == ss_connected) { /* decrypt and forward data to client side */ if (output_size < to->wm_write.high) { if (input_size) decrypt_buffer(client, from, to); if (bufferevent_enable(from, EV_READ) == -1) redsocks_log_errno(client, LOG_ERR, "bufferevent_enable"); } else { if (bufferevent_disable(from, EV_READ) == -1) redsocks_log_errno(client, LOG_ERR, "bufferevent_disable"); } } else { redsocks_drop_client(client); } }
int decode_out(Gzb64* gzb64, unsigned char* buf, const size_t length) { int zret, ret; /* should be guaranteed at least length after inflate */ int gz_in_bytes = evbuffer_get_contiguous_space(gzb64->decode_output_buffer); unsigned char* gzin_buf = evbuffer_pullup(gzb64->decode_output_buffer, gz_in_bytes ); if(DEBUG) hex_debug(gzin_buf, gz_in_bytes); gzb64->gz_decode_strm.next_in = gzin_buf; gzb64->gz_decode_strm.avail_in = gz_in_bytes; gzb64->gz_decode_strm.next_out = buf; gzb64->gz_decode_strm.avail_out = length; zret = inflate (& gzb64->gz_decode_strm, Z_NO_FLUSH); if(zret < 0) zerr(zret); evbuffer_drain(gzb64->decode_output_buffer, gz_in_bytes - gzb64->gz_decode_strm.avail_in); ret = length - gzb64->gz_decode_strm.avail_out; if(gzb64->decoded_last_chunk && 0 == ret) { resetDecoder(gzb64); } return ret; }
static void ss_relay_writecb(struct bufferevent *buffev, void *_arg) { redsocks_client *client = _arg; struct bufferevent * from = client->client; struct bufferevent * to = buffev; size_t input_size = evbuffer_get_contiguous_space(bufferevent_get_input(from)); size_t output_size = evbuffer_get_length(bufferevent_get_output(to)); assert(buffev == client->relay); redsocks_touch_client(client); if (process_shutdown_on_write_(client, from, to)) return; if (client->state == ss_connected) { /* encrypt and forward data received from client side */ if (output_size < to->wm_write.high) { if (input_size) encrypt_buffer(client, from, to); if (!(client->client_evshut & EV_READ) && bufferevent_enable(from, EV_READ) == -1) redsocks_log_errno(client, LOG_ERR, "bufferevent_enable"); } } else { redsocks_drop_client(client); } }
static void decrypt_buffer(redsocks_client * client, struct bufferevent * from, struct bufferevent * to) { // To reduce memory copy, just decrypt one block a time struct evbuffer * buf_in = bufferevent_get_input(from); size_t input_size = evbuffer_get_contiguous_space(buf_in); char * input; if (!input_size) return; input = (char *)evbuffer_pullup(buf_in, input_size); encrypt_mem(client, input, input_size, to, 1); evbuffer_drain(buf_in, input_size); }
int decode_in_ev(Gzb64* gzb64, struct evbuffer* input) { int contiguous; while(evbuffer_get_length(input) > 0 ) { contiguous = evbuffer_get_contiguous_space(input); if( contiguous < evbuffer_get_length(input) ) { evbuffer_remove_buffer(input, gzb64->decode_input_buffer, contiguous); decode(gzb64, false); } else { /* last (only) block */ evbuffer_remove_buffer(input, gzb64->decode_input_buffer, contiguous); } } return decode(gzb64, true); }
int encode_in_ev(Gzb64* gzb64, struct evbuffer* input) { int contiguous; unsigned char* input_block; while(evbuffer_get_length(input) > 0) { contiguous = evbuffer_get_contiguous_space(input); input_block = evbuffer_pullup(input, contiguous); if( contiguous < evbuffer_get_length(input) ) { encode_in(gzb64, &input_block[0], contiguous, false); evbuffer_drain(input, contiguous); } else { /* last (only) block */ encode_in(gzb64, &input_block[0], contiguous, true); evbuffer_drain(input, contiguous); } } return 0; }
static int decode(Gzb64* gzb64, bool last) { int b64in_size; struct evbuffer_iovec v[2]; int n, i; size_t n_to_add = BUFF_SIZE; if( last ) { b64in_size = evbuffer_get_length(gzb64->decode_input_buffer); /* dump everything in */ gzb64->decoded_last_chunk = true; } else { int contiguous = evbuffer_get_contiguous_space(gzb64->decode_input_buffer); b64in_size = contiguous - (contiguous % 4); /* must be mutliple of 4 */ } if(DEBUG) printf("Decode In:%zu\n", evbuffer_get_length(gzb64->decode_input_buffer)); unsigned char* b64in_buf = evbuffer_pullup(gzb64->decode_input_buffer, b64in_size); BIO *b64_src_temp = BIO_new_mem_buf(b64in_buf, b64in_size); gzb64->b64_decoder = BIO_push(gzb64->b64_decoder, b64_src_temp); int b64_output_len = BUFF_SIZE; while(b64_output_len == BUFF_SIZE) { /* Reserve BUFF_SIZE bytes.*/ n = evbuffer_reserve_space(gzb64->decode_output_buffer, n_to_add, v, 2); if (n<=0) return -1; /* Unable to reserve the space for some reason. */ for (i=0; i<n && n_to_add > 0; ++i) { size_t len = v[i].iov_len; if (len > n_to_add) /* Don't write more than n_to_add bytes. */ len = n_to_add; b64_output_len = BIO_read(gzb64->b64_decoder, v[i].iov_base, len); if ( b64_output_len < 0) { /* If there was a problem during data generation, we can just stop here; no data will be committed to the buffer. */ return -1; } /* Set iov_len to the number of bytes we actually wrote, so we don't commit too much. */ v[i].iov_len = b64_output_len; if(DEBUG) printf("Decode B64 Out:%d\n", b64_output_len); } /* We commit the space here. Note that we give it 'i' (the number of vectors we actually used) rather than 'n' (the number of vectors we had available. */ if (evbuffer_commit_space(gzb64->decode_output_buffer, v, i) < 0) return -1; /* Error committing */ } if(DEBUG) printf("Inflate In:%zu\n", evbuffer_get_length(gzb64->decode_output_buffer)); BIO_pop(gzb64->b64_decoder); BIO_free(b64_src_temp); BIO_reset(gzb64->b64_decoder); evbuffer_drain(gzb64->decode_input_buffer, b64in_size); return 0; }