📄 tunnel.c
字号:
/* * tunnel.c - port forward implementations * * Copyright (C) 2000, 2001 Stefan Jahn <stefan@lkcc.org> * * This 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 2, or (at your option) * any later version. * * This software 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 package; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * $Id: tunnel.c,v 1.26 2001/07/03 10:43:31 ela Exp $ * */#if HAVE_CONFIG_H# include <config.h>#endif#if ENABLE_TUNNEL#define _GNU_SOURCE#include <assert.h>#include <stdio.h>#include <string.h>#include <sys/types.h>#include <time.h>#ifdef __MINGW32__# include <winsock2.h>#endif#ifndef __MINGW32__# include <sys/socket.h># include <netinet/in.h># include <arpa/inet.h>#endif#include "libserveez.h"#include "tunnel.h"/* * The default tunnel server configuration. */tnl_config_t tnl_config = { NULL, /* the source port to forward from */ NULL, /* target port to forward to */ NULL /* the source client socket hash */};/* * Defining configuration file associations with key-value-pairs. */svz_key_value_pair_t tnl_config_prototype [] = { SVZ_REGISTER_PORTCFG ("source", tnl_config.source, SVZ_ITEM_NOTDEFAULTABLE), SVZ_REGISTER_PORTCFG ("target", tnl_config.target, SVZ_ITEM_NOTDEFAULTABLE), SVZ_REGISTER_END ()};/* * Definition of this server. */svz_servertype_t tnl_server_definition ={ "tunnel server", "tunnel", tnl_global_init, tnl_init, tnl_detect_proto, tnl_connect_socket, tnl_finalize, tnl_global_finalize, NULL, NULL, NULL, tnl_handle_request_udp_source, &tnl_config, sizeof (tnl_config), tnl_config_prototype};/* * The tunnel server's global initializer. */inttnl_global_init (svz_servertype_t *server){ return 0;}/* * The tunnel server's global finalizer. */inttnl_global_finalize (svz_servertype_t *server){ return 0;}/* * Tunnel server instance initializer. Check the configuration. */inttnl_init (svz_server_t *server){ tnl_config_t *cfg = server->cfg; struct sockaddr_in *addr; /* protocol supported ? */ if (!(cfg->source->proto & (PROTO_TCP|PROTO_ICMP|PROTO_UDP|PROTO_PIPE)) || !(cfg->target->proto & (PROTO_TCP|PROTO_ICMP|PROTO_UDP|PROTO_PIPE))) { svz_log (LOG_ERROR, "tunnel: protocol not supported\n"); return -1; } /* check identity of source and target port configurations */ if (svz_portcfg_equal (cfg->source, cfg->target)) { svz_log (LOG_ERROR, "tunnel: source and target identical\n"); return -1; } if (!(cfg->target->proto & PROTO_PIPE)) { /* broadcast target ip address not allowed */ addr = svz_portcfg_addr (cfg->target); if (addr->sin_addr.s_addr == INADDR_ANY) { svz_log (LOG_ERROR, "tunnel: broadcast target ip not allowed\n"); return -1; } } /* create source client hash (for UDP and ICMP only) */ cfg->client = svz_hash_create (4); /* assign the appropriate handle request routine of the server */ if (cfg->source->proto & PROTO_UDP) server->handle_request = tnl_handle_request_udp_source; if (cfg->source->proto & PROTO_ICMP) server->handle_request = tnl_handle_request_icmp_source; return 0;}/* * The tunnel server instance finalizer. */inttnl_finalize (svz_server_t *server){ tnl_config_t *cfg = server->cfg; tnl_connect_t **source; int n; /* release source connection hash if necessary */ if ((source = (tnl_connect_t **) svz_hash_values (cfg->client)) != NULL) { for (n = 0; n < svz_hash_size (cfg->client); n++) { svz_free (source[n]); } svz_hash_xfree (source); } svz_hash_destroy (cfg->client); return 0;}/* * Create a hash string (key) for the source client hash. Identifiers * are the remote ip address and port. */static char *tnl_addr (svz_socket_t *sock){ static char addr[24]; sprintf (addr, "%s:%u", svz_inet_ntoa (sock->remote_addr), ntohs (sock->remote_port)); return addr;}/* * Release referring tunnel structure. */static voidtnl_free_connect (svz_socket_t *sock){ if (sock->data) { svz_free (sock->data); sock->data = NULL; }}/* * Create a referring tunnel connection structure. */static tnl_connect_t *tnl_create_connect (void){ tnl_connect_t *source; source = svz_malloc (sizeof (tnl_connect_t)); memset (source, 0, sizeof (tnl_connect_t)); return source;}/* * Depending on the given socket structure target flag this routine * tries to connect to the servers target configuration and delivers a * new socket structure or NULL if it failed. */ static svz_socket_t *tnl_create_socket (svz_socket_t *sock, int source){ tnl_config_t *cfg = sock->cfg; unsigned long ip = 0; unsigned short port = 0; svz_socket_t *xsock = NULL; struct sockaddr_in *addr; /* get host and target ip if necessary */ if (!(cfg->target->proto & PROTO_PIPE)) { addr = svz_portcfg_addr (cfg->target); ip = addr->sin_addr.s_addr; port = addr->sin_port; } /* * Depending on the target configuration we assign different * callbacks, set other flags and use various connection routines. */ switch (cfg->target->proto) { case PROTO_TCP: sock->userflags |= TNL_FLAG_TGT_TCP; break; case PROTO_UDP: sock->userflags |= TNL_FLAG_TGT_UDP; break; case PROTO_ICMP: sock->userflags |= TNL_FLAG_TGT_ICMP; break; case PROTO_PIPE: sock->userflags |= TNL_FLAG_TGT_PIPE; break; default: svz_log (LOG_ERROR, "tunnel: invalid target configuration\n"); return NULL; } /* target is a TCP connection */ if (sock->userflags & TNL_FLAG_TGT_TCP) { if ((xsock = svz_tcp_connect (ip, port)) == NULL) { svz_log (LOG_ERROR, "tunnel: tcp: cannot connect to %s:%u\n", svz_inet_ntoa (ip), ntohs (port)); return NULL; }#if ENABLE_DEBUG svz_log (LOG_DEBUG, "tunnel: tcp: connecting to %s:%u\n", svz_inet_ntoa (ip), ntohs (port));#endif /* ENABLE_DEBUG */ xsock->check_request = tnl_check_request_tcp_target; svz_sock_resize_buffers (xsock, UDP_BUF_SIZE, UDP_BUF_SIZE); } /* target is an UDP connection */ else if (sock->userflags & TNL_FLAG_TGT_UDP) { if ((xsock = svz_udp_connect (ip, port)) == NULL) { svz_log (LOG_ERROR, "tunnel: udp: cannot connect to %s:%u\n", svz_inet_ntoa (ip), ntohs (port)); return NULL; }#if ENABLE_DEBUG svz_log (LOG_DEBUG, "tunnel: udp: connecting to %s:%u\n", svz_inet_ntoa (ip), ntohs (port));#endif /* ENABLE_DEBUG */ xsock->handle_request = tnl_handle_request_udp_target; xsock->idle_func = tnl_idle; xsock->idle_counter = TNL_TIMEOUT; } /* target is an ICMP connection */ else if (sock->userflags & TNL_FLAG_TGT_ICMP) { if ((xsock = svz_icmp_connect (ip, port, cfg->target->icmp_type)) == NULL) { svz_log (LOG_ERROR, "tunnel: icmp: cannot connect to %s\n", svz_inet_ntoa (ip)); return NULL; }#if ENABLE_DEBUG svz_log (LOG_DEBUG, "tunnel: icmp: connecting to %s\n", svz_inet_ntoa (ip));#endif /* ENABLE_DEBUG */ xsock->handle_request = tnl_handle_request_icmp_target; xsock->idle_func = tnl_idle; xsock->idle_counter = TNL_TIMEOUT; } /* target is a pipe connection */ else if (sock->userflags & TNL_FLAG_TGT_PIPE) { if ((xsock = svz_pipe_connect (&cfg->target->pipe_recv, &cfg->target->pipe_send)) == NULL) { svz_log (LOG_ERROR, "tunnel: pipe: cannot connect to %s\n", cfg->target->pipe_send.name); return NULL; }#if ENABLE_DEBUG svz_log (LOG_DEBUG, "tunnel: pipe: connecting to %s\n", cfg->target->pipe_send.name);#endif /* ENABLE_DEBUG */ xsock->check_request = tnl_check_request_pipe_target; svz_sock_resize_buffers (xsock, UDP_BUF_SIZE, UDP_BUF_SIZE); } xsock->cfg = cfg; xsock->flags |= SOCK_FLAG_NOFLOOD; xsock->userflags = (sock->userflags | source) & ~(TNL_FLAG_TGT); xsock->disconnected_socket = tnl_disconnect_target; return xsock;}/* * Forward a given packet with a certain length to a target connection. * This routine can be used by all source connection handler passing * the targets socket and its own userflags. */static inttnl_send_request_source (svz_socket_t *sock, char *packet, int len, int flag){ /* target is TCP or PIPE */ if (flag & (TNL_FLAG_TGT_TCP | TNL_FLAG_TGT_PIPE)) { if (svz_sock_write (sock, packet, len) == -1) return -1; } /* target is UDP */ else if (flag & TNL_FLAG_TGT_UDP) { if (svz_udp_write (sock, packet, len) == -1) return -1; } /* target is ICMP */ else if (flag & TNL_FLAG_TGT_ICMP) { if (svz_icmp_write (sock, packet, len) == -1) return -1; } return 0;}/* * Forward a given packet with a certain length to a source connection. * This routine can be used by all target connection handler passing * the sources socket and its own userflags. */static inttnl_send_request_target (svz_socket_t *sock, char *packet, int len, int flag){ /* source is TCP or PIPE */ if (flag & (TNL_FLAG_SRC_TCP | TNL_FLAG_SRC_PIPE)) { if (svz_sock_write (sock, packet, len) == -1) return -1; } /* source is UDP */ else if (flag & TNL_FLAG_SRC_UDP) { if (svz_udp_write (sock, packet, len) == -1) return -1; } /* source is ICMP */ else if (flag & TNL_FLAG_SRC_ICMP) { if (svz_icmp_write (sock, packet, len) == -1) return -1; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -