//vio_proxy.c: /* * Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2011-2012 * * This file is part of libroar a part of RoarAudio, * a cross-platform sound system for both, home and professional use. * See README for details. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * libroar 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 this software; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * NOTE for everyone want's to change something and send patches: * read README and HACKING! There a addition information on * the license of this document you need to read before you send * any patches. * * NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc * or libpulse*: * The libs libroaresd, libroararts and libroarpulse link this lib * and are therefore GPL. Because of this it may be illigal to use * them with any software that uses libesd, libartsc or libpulse*. */ #include "libroar.h" int roar_vio_proxy_init_def(struct roar_vio_defaults * def, char * dstr, enum roar_vio_proxy_type type, struct roar_vio_defaults * odef) { int hint = -1; (void)type; // TODO: generate hints from type. ROAR_DBG("roar_vio_proxy_init_def(def=%p, dstr='%s', type=%i, odef=%p) = ?", def, dstr, (int)type, odef); if ( roar_vio_dstr_init_defaults(def, ROAR_VIO_DEF_TYPE_SOCKET, O_RDWR, 0644) == -1 ) return -1; if ( roar_vio_socket_init_dstr_def(def, dstr, hint, odef == NULL ? SOCK_STREAM : odef->d.socket.type, odef) == -1 ) { ROAR_DBG("roar_vio_proxy_init_def(def=%p, dstr='%s', type=%i, odef=%p) = -1", def, dstr, (int)type, odef); return -1; } ROAR_DBG("roar_vio_proxy_init_def(def=%p, dstr='%s', type=%i, odef=%p) = 0", def, dstr, (int)type, odef); return 0; } static int roar_vio_proxy_ctl (struct roar_vio_calls * vio, roar_vio_ctl_t cmd, void * data) { if ( cmd == ROAR_VIO_CTL_GET_NAME ) { *(char **)data = "proxy"; return 0; } return roar_vio_pass_ctl(vio, cmd, data); } static int init_socks4(struct roar_vio_calls * dst, enum roar_vio_proxy_type type, struct roar_vio_defaults * odef) { char buf[9] = { 0x04, // [0] Version 0x01, // [1] mode=connect (listen is 0x02) 0, 0, 0, 0, // [2..5] host IP 0, // [6] Port MSB 0, // [7] Port LSB 0x00 // [8] EOS (\0) of username }; enum roar_vio_proxy_type needed_type = ROAR_VIO_PROXY_INVALID; ROAR_DBG("init_socks4(dst=%p, type=%i, odef=%p{.d.socket={.domain=%i, .type=%i, .host='%s'}}) = ?", dst, (int)type, odef, odef->d.socket.domain, odef->d.socket.type, odef->d.socket.host); switch (odef->d.socket.domain) { #ifdef ROAR_HAVE_IPV4 case AF_INET: needed_type = ROAR_VIO_PROXY_SOCKS4; break; #endif #ifdef ROAR_HAVE_LIBDNET case AF_DECnet: if ( odef->d.socket.sa.dn.sdn_objnum == 0 ) { needed_type = ROAR_VIO_PROXY_SOCKS4d; } else { needed_type = ROAR_VIO_PROXY_SOCKS4; } break; #endif #ifdef ROAR_HAVE_IPV6 case AF_INET6: #endif #ifdef ROAR_HAVE_IPX case AF_IPX: #endif #ifdef ROAR_HAVE_UNIX case AF_UNIX: #endif default: roar_err_set(ROAR_ERROR_AFNOTSUP); return -1; break; } if ( needed_type == ROAR_VIO_PROXY_SOCKS4 && type != needed_type ) needed_type = type; if ( needed_type != type ) { roar_err_set(ROAR_ERROR_INVAL); return -1; } switch (odef->d.socket.domain) { #ifdef ROAR_HAVE_IPV4 case AF_INET: if ( roar_vio_socket_init_inet4host_def(odef) == -1 ) return -1; buf[2] = ((char*)&(odef->d.socket.sa.in.sin_port))[0]; buf[3] = ((char*)&(odef->d.socket.sa.in.sin_port))[1]; buf[4] = ((char*)&(odef->d.socket.sa.in.sin_addr.s_addr))[0]; buf[5] = ((char*)&(odef->d.socket.sa.in.sin_addr.s_addr))[1]; buf[6] = ((char*)&(odef->d.socket.sa.in.sin_addr.s_addr))[2]; buf[7] = ((char*)&(odef->d.socket.sa.in.sin_addr.s_addr))[3]; ROAR_DBG("init_socks4(dst=%p, type=%i, odef=%p{.d.socket={.domain=%i, .type=%i, .host='%s'}}): buf[]={%i, %i, %i, %i, %i, %i, %i, %i, %i}", dst, (int)type, odef, odef->d.socket.domain, odef->d.socket.type, odef->d.socket.host, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8]); break; #endif #ifdef ROAR_HAVE_LIBDNET case AF_DECnet: if ( type == ROAR_VIO_PROXY_SOCKS4 ) { buf[2] = 0; buf[3] = odef->d.socket.sa.dn.sdn_objnum; buf[4] = 0; buf[5] = 2; buf[6] = odef->d.socket.sa.dn.sdn_nodeaddr[0]; buf[7] = odef->d.socket.sa.dn.sdn_nodeaddr[1]; } else { roar_err_set(ROAR_ERROR_NOTSUP); return -1; } break; #endif } if ( roar_vio_write(dst, buf, sizeof(buf)) != (ssize_t)sizeof(buf) ) return -1; if ( roar_vio_read(dst, buf, 8) != (ssize_t)8 ) return -1; if ( buf[1] != 0x5a ) { roar_err_set(ROAR_ERROR_UNKNOWN); return -1; } return 0; } int roar_vio_open_proxy (struct roar_vio_calls * calls, struct roar_vio_calls * dst, enum roar_vio_proxy_type type, struct roar_vio_defaults * odef) { int init_only = -1; int (*init)(struct roar_vio_calls * dst, enum roar_vio_proxy_type type, struct roar_vio_defaults * odef) = NULL; ROAR_DBG("roar_vio_open_proxy(calls=%p, dst=%p, type=%i, odef=%p{.type=%i}) = ?", calls, dst, (int)type, odef, (int)odef->type); if ( odef->type != ROAR_VIO_DEF_TYPE_SOCKET ) { roar_err_set(ROAR_ERROR_NOTSOCK); return -1; } switch (type) { case ROAR_VIO_PROXY_NONE: init_only = 1; init = NULL; break; case ROAR_VIO_PROXY_SOCKS: case ROAR_VIO_PROXY_SOCKS4: case ROAR_VIO_PROXY_SOCKS4a: case ROAR_VIO_PROXY_SOCKS4d: init_only = 1; init = init_socks4; break; #ifndef DEBUG default: break; #endif } if ( init_only == 1 ) { if ( init != NULL ) if ( init(dst, type, odef) == -1 ) return -1; if ( roar_vio_open_pass(calls, dst) == -1 ) return -1; calls->ctl = roar_vio_proxy_ctl; return 0; } else { roar_err_set(ROAR_ERROR_NOTSUP); return -1; } } // DSTR interface: static enum roar_vio_proxy_type _dstrtype2proxytype(struct roar_vio_dstr_chain * chainelement) { switch (chainelement->type) { case ROAR_VIO_DSTR_OBJT_SOCKS: return ROAR_VIO_PROXY_SOCKS; break; case ROAR_VIO_DSTR_OBJT_SOCKS4: return ROAR_VIO_PROXY_SOCKS4; break; case ROAR_VIO_DSTR_OBJT_SOCKS4A: return ROAR_VIO_PROXY_SOCKS4a; break; case ROAR_VIO_DSTR_OBJT_SOCKS4D: return ROAR_VIO_PROXY_SOCKS4d; break; case ROAR_VIO_DSTR_OBJT_SOCKS5: return ROAR_VIO_PROXY_SOCKS5; break; default: return ROAR_VIO_PROXY_INVALID; break; } } int roar_vio_proxy_setdef(struct roar_vio_dstr_chain * cur, struct roar_vio_dstr_chain * next) { next->def = &(next->store_def); return roar_vio_proxy_init_def(next->def, cur->dst, _dstrtype2proxytype(cur), cur->def); } int roar_vio_proxy_openvio(struct roar_vio_calls * calls, struct roar_vio_calls * dst, struct roar_vio_dstr_chain * cur, struct roar_vio_dstr_chain * next) { return roar_vio_open_proxy(calls, dst, _dstrtype2proxytype(cur), cur->def); } //ll