/* * Copyright (C) 2010-2015 Mamadou DIOP. * Copyright (C) 2015 Doubango Telecom. * * This file is part of Open Source Doubango Framework. * * DOUBANGO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * DOUBANGO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DOUBANGO. * */ #include "tnet_proxy_plugin.h" #include "tsk_memory.h" #include "tsk_string.h" #include "tsk_debug.h" #if !defined(TNET_PROXY_NODE_MAX_PLUGINS) # define TNET_PROXY_NODE_MAX_PLUGINS 10 #endif const tnet_proxy_node_plugin_def_t* __tnet_proxy_node_plugins[TNET_PROXY_NODE_MAX_PLUGINS] = {0}; tsk_bool_t tnet_proxy_node_is_nettransport_supported(enum tnet_proxy_type_e proxy_type, enum tnet_socket_type_e socket_type) { switch (proxy_type) { case tnet_proxy_type_http: case tnet_proxy_type_https: return TNET_SOCKET_TYPE_IS_STREAM(socket_type); case tnet_proxy_type_socks4: case tnet_proxy_type_socks4a: return TNET_SOCKET_TYPE_IS_STREAM(socket_type) && TNET_SOCKET_TYPE_IS_IPV4(socket_type); case tnet_proxy_type_socks5: // SOCKS5 adds support for UDP and IPv6 return TNET_SOCKET_TYPE_IS_STREAM(socket_type) || TNET_SOCKET_TYPE_IS_DGRAM(socket_type);// for now we don't support socks for UDP (just like a browser) default: return tsk_false; } } int tnet_proxy_node_init(tnet_proxy_node_t* self) { if (self) { self->socket.fd = TNET_INVALID_FD; self->socket.type = tnet_socket_type_invalid; } return 0; } int tnet_proxy_node_configure(tnet_proxy_node_t* self, ...) { va_list ap; int ret = 0; if (!self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } va_start(ap, self); ret = tnet_proxy_node_configure_2(self, &ap); va_end(ap); return ret; } int tnet_proxy_node_configure_2(tnet_proxy_node_t* self, va_list* app) { int ret = 0; tnet_proxy_node_param_type_t ptype; if (!self || !app) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } while ((ptype = va_arg(*app, tnet_proxy_node_param_type_t)) != tnet_proxy_node_param_type_null) { switch (ptype) { case tnet_proxy_node_param_type_destination_address: case tnet_proxy_node_param_type_proxy_address: { // (const char*)(HOST_STR), (int)(PORT_INT) const char* HOST_STR = va_arg(*app, const char*); int PORT_INT = va_arg(*app, int); if (PORT_INT < 1 || PORT_INT > 0xFFF) { TSK_DEBUG_ERROR("Invalid value for port number: %d", PORT_INT); ret = -3; goto bail; } if (ptype == tnet_proxy_node_param_type_destination_address) { tsk_strupdate(&self->dst_host, HOST_STR); self->dst_port = (tnet_port_t)PORT_INT; } else { tsk_strupdate(&self->proxy_host, HOST_STR); self->proxy_port = (tnet_port_t)PORT_INT; } break; } case tnet_proxy_node_param_type_ipv6: { /* (tsk_bool_t)(IPV6_BOOL) */ self->ipv6 = va_arg(*app, tsk_bool_t); break; } case tnet_proxy_node_param_type_credentials: { /* (const char*)(LOGIN_STR), (const char*)(PASSWORD_STR) */ const char* LOGIN_STR = va_arg(*app, const char*); const char* PASSWORD_STR = va_arg(*app, const char*); tsk_strupdate(&self->login, LOGIN_STR); tsk_strupdate(&self->password, PASSWORD_STR); break; } case tnet_proxy_node_param_type_socket: { /* (tnet_fd_t)(FD_FD), (enum tnet_socket_type_e)(type) */ self->socket.fd = va_arg(*app, tnet_fd_t); self->socket.type = va_arg(*app, enum tnet_socket_type_e); break; } #if TNET_UNDER_APPLE case tnet_proxy_node_param_type_cfstreams: { /* (CFReadStreamRef)(READ_CFSTREAM), (CFWriteStreamRef)(WRITE_CFSTREAM) */ CFReadStreamRef READ_CFSTREAM = va_arg(*app, CFReadStreamRef); CFWriteStreamRef WRITE_CFSTREAM = va_arg(*app, CFWriteStreamRef); if (self->cf_read_stream) { CFRelease(self->cf_read_stream), self->cf_read_stream = tsk_null; } if (self->cf_write_stream) { CFRelease(self->cf_write_stream), self->cf_write_stream = tsk_null; } if (READ_CFSTREAM) { self->cf_read_stream = (CFReadStreamRef)CFRetain(READ_CFSTREAM); } if (WRITE_CFSTREAM) { self->cf_write_stream = (CFWriteStreamRef)CFRetain(WRITE_CFSTREAM); } break; } #endif /* TNET_UNDER_APPLE */ default: { TSK_DEBUG_ERROR("%d not valid param type", ptype); ret = -2; goto bail; } } } bail: return ret; } int tnet_proxy_node_start_handshaking(tnet_proxy_node_t* self) { if (!self || !self->plugin || !self->plugin->start_handshaking) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } return self->plugin->start_handshaking(self); } int tnet_proxy_node_set_handshaking_data(tnet_proxy_node_t* self, const void* data_ptr, tsk_size_t data_size) { if (!self || !data_ptr || !data_size || !self->plugin || !self->plugin->set_handshaking_data) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } return self->plugin->set_handshaking_data(self, data_ptr, data_size); } int tnet_proxy_node_get_handshaking_pending_data(tnet_proxy_node_t* self, void** data_pptr, tsk_size_t* data_psize) { if (!self || !data_pptr || !data_psize || !self->plugin || !self->plugin->get_handshaking_pending_data) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } return self->plugin->get_handshaking_pending_data(self, data_pptr, data_psize); } int tnet_proxy_node_get_handshaking_completed(tnet_proxy_node_t* self, tsk_bool_t* completed) { if (!self || !completed || !self->plugin || !self->plugin->get_handshaking_completed) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } return self->plugin->get_handshaking_completed(self, completed); } int tnet_proxy_node_deinit(tnet_proxy_node_t* self) { if (self) { TSK_FREE(self->dst_host); TSK_FREE(self->proxy_host); TSK_FREE(self->login); TSK_FREE(self->password); #if TNET_UNDER_APPLE if (self->cf_read_stream) { CFRelease(self->cf_read_stream), self->cf_read_stream = tsk_null; } if (self->cf_write_stream) { CFRelease(self->cf_write_stream), self->cf_write_stream = tsk_null; } #endif } return 0; } int tnet_proxy_node_plugin_register(const tnet_proxy_node_plugin_def_t* plugin) { tsk_size_t i; if (!plugin || tsk_strnullORempty(plugin->desc)) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } /* add or replace the plugin */ for (i = 0; idesc); return 0; } } TSK_DEBUG_ERROR("There are already %d network proxy node plugins.", TNET_PROXY_NODE_MAX_PLUGINS); return -2; } int tnet_proxy_node_plugin_unregister(const tnet_proxy_node_plugin_def_t* plugin) { tsk_size_t i; tsk_bool_t found = tsk_false; if (!plugin) { TSK_DEBUG_ERROR("Invalid Parameter"); return -1; } /* find the plugin to unregister */ for (i = 0; idesc); __tnet_proxy_node_plugins[i] = tsk_null; found = tsk_true; break; } } /* compact */ if (found) { for (; i<(TNET_PROXY_NODE_MAX_PLUGINS - 1); i++) { if (__tnet_proxy_node_plugins[i+1]) { __tnet_proxy_node_plugins[i] = __tnet_proxy_node_plugins[i+1]; } else { break; } } __tnet_proxy_node_plugins[i] = tsk_null; } return (found ? 0 : -2); } tsk_size_t tnet_proxy_node_plugin_registry_count() { tsk_size_t count; for(count = 0; count < TNET_PROXY_NODE_MAX_PLUGINS && __tnet_proxy_node_plugins[count]; ++count) ; return count; } tnet_proxy_node_t* tnet_proxy_node_create(enum tnet_proxy_type_e type) { tsk_size_t i; tnet_proxy_node_t* node = tsk_null; for (i = 0; itype & type) == type) { if ((node = tsk_object_new(__tnet_proxy_node_plugins[i]->objdef))) { node->type = type; node->plugin = __tnet_proxy_node_plugins[i]; break; } } } return node; }