static void socks5_read_auth_methods(struct bufferevent *buffev, redsocks_client *client, socks5_client *socks5) { socks5_method_reply reply; const char *error = NULL; if (redsocks_read_expected(client, buffev->input, &reply, sizes_equal, sizeof(reply)) < 0) return; error = socks5_is_known_auth_method(&reply, socks5->do_password); if (error) { redsocks_log_error(client, LOG_NOTICE, "socks5_is_known_auth_method: %s", error); redsocks_drop_client(client); } else if (reply.method == socks5_auth_none) { redsocks_write_helper( buffev, client, socks5_mkconnect, socks5_request_sent, sizeof(socks5_reply) ); } else if (reply.method == socks5_auth_password) { redsocks_write_helper( buffev, client, socks5_mkpassword, socks5_auth_sent, sizeof(socks5_auth_reply) ); } }
static void socks5_write_cb(struct bufferevent *buffev, void *_arg) { redsocks_client *client = _arg; redsocks_touch_client(client); if (client->state == socks5_new) { redsocks_write_helper( buffev, client, socks5_mkmethods, socks5_method_sent, sizeof(socks5_method_reply) ); } }
static void socks4_write_cb(struct bufferevent *buffev, void *_arg) { redsocks_client *client = _arg; redsocks_touch_client(client); if (client->state == socks4_new) { redsocks_write_helper( buffev, client, socks4_mkconnect, socks4_request_sent, sizeof(socks4_reply) ); } else if (client->state >= socks4_request_sent) { bufferevent_disable(buffev, EV_WRITE); } }
static void socks5_read_reply(struct bufferevent *buffev, redsocks_client *client, socks5_client *socks5) { socks5_reply reply; if (redsocks_read_expected(client, buffev->input, &reply, sizes_greater_equal, sizeof(reply)) < 0) return; if (reply.ver != socks5_ver) { redsocks_log_error(client, LOG_NOTICE, "Socks5 server reported unexpected reply version..."); redsocks_drop_client(client); } else if (reply.status == socks5_status_succeeded) { socks5_state nextstate; size_t len; if (reply.addrtype == socks5_addrtype_ipv4) { len = socks5->to_skip = sizeof(socks5_addr_ipv4); nextstate = socks5_skip_address; } else if (reply.addrtype == socks5_addrtype_ipv6) { len = socks5->to_skip = sizeof(socks5_addr_ipv6); nextstate = socks5_skip_address; } else if (reply.addrtype == socks5_addrtype_domain) { socks5_addr_domain domain; len = sizeof(domain.size); nextstate = socks5_skip_domain; } else { redsocks_log_error(client, LOG_NOTICE, "Socks5 server reported unexpected address type..."); redsocks_drop_client(client); return; } redsocks_write_helper( buffev, client, NULL, nextstate, len ); } else { redsocks_log_error(client, LOG_NOTICE, "Socks5 server status: %s (%i)", /* 0 <= reply.status && */ reply.status < SIZEOF_ARRAY(socks5_strstatus) ? socks5_strstatus[reply.status] : "?", reply.status); redsocks_drop_client(client); } }
static void socks5_read_auth_reply(struct bufferevent *buffev, redsocks_client *client, socks5_client *socks5) { socks5_auth_reply reply; if (redsocks_read_expected(client, buffev->input, &reply, sizes_equal, sizeof(reply)) < 0) return; if (reply.ver != socks5_password_ver) { redsocks_log_error(client, LOG_NOTICE, "Socks5 server reported unexpected auth reply version..."); redsocks_drop_client(client); } else if (reply.status == socks5_password_passed) redsocks_write_helper( buffev, client, socks5_mkconnect, socks5_request_sent, sizeof(socks5_reply) ); else redsocks_drop_client(client); }
static void socks5_read_cb(struct bufferevent *buffev, void *_arg) { redsocks_client *client = _arg; socks5_client *socks5 = red_payload(client); redsocks_touch_client(client); if (client->state == socks5_method_sent) { socks5_read_auth_methods(buffev, client, socks5); } else if (client->state == socks5_auth_sent) { socks5_read_auth_reply(buffev, client, socks5); } else if (client->state == socks5_request_sent) { socks5_read_reply(buffev, client, socks5); } else if (client->state == socks5_skip_domain) { socks5_addr_ipv4 ipv4; // all socks5_addr*.port are equal uint8_t size; if (redsocks_read_expected(client, buffev->input, &size, sizes_greater_equal, sizeof(size)) < 0) return; socks5->to_skip = size + sizeof(ipv4.port); redsocks_write_helper( buffev, client, NULL, socks5_skip_address, socks5->to_skip ); } else if (client->state == socks5_skip_address) { uint8_t data[socks5->to_skip]; if (redsocks_read_expected(client, buffev->input, data, sizes_greater_equal, socks5->to_skip) < 0) return; redsocks_start_relay(client); } else { redsocks_drop_client(client); } }