📄 tunnel.c
字号:
/* rtptunnel - A UDP to TCP tunneling program Copyright (C) 1999 Roland Dreier This program 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 of the License, or (at your option) any later version. This program 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 program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. $Id: tunnel.c 1.3 Sat, 04 Dec 1999 16:05:07 -0600 dreier $*/#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <ctype.h>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/time.h>#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <netdb.h>#include <netinet/in.h>#include <arpa/inet.h>#include <popt.h>enum { DEFAULT_RTP_PORT = 5004, DEFAULT_TUNNEL_PORT = 5685};enum { MAX_PORTS = 2, MAX_PACKET_SIZE = 2000};int Tunnel_Port = DEFAULT_TUNNEL_PORT;int Recv_Rtp_Port = DEFAULT_RTP_PORT;int Send_Rtp_Port = DEFAULT_RTP_PORT;char *Tunnel_Hostname = NULL;char *Send_Rtp_String = NULL;char *Send_Hostname = NULL;struct poptOption optionsTable[] = { { "tunnel-port", 't', POPT_ARG_INT, &Tunnel_Port, 0, "Set TCP port for tunnel", "port" }, { "recv-rtp", 'r', POPT_ARG_INT, &Recv_Rtp_Port, 0, "Set RTP port to listen on", "port" }, { "send-rtp", 's', POPT_ARG_STRING, &Send_Rtp_String, 0, "Set RTP host and port to send to", "[hostname]:[port]" }, { "call", 'c', POPT_ARG_STRING, &Tunnel_Hostname, 0, "Tunnel to remote computer", "hostname" }, POPT_AUTOHELP { NULL, 0, 0, NULL, 0 }};int Tunnel_Sock;int Num_Ports;int Recv_Port[MAX_PORTS], Send_Port[MAX_PORTS];int Recv_Sock[MAX_PORTS], Send_Sock;static voidfind_host(char *host_name, struct in_addr *address){ struct hostent *host; if (inet_aton(host_name, address)) { return; } else { host = gethostbyname(host_name); } if (!host) { herror("error looking up host"); exit(1); } memmove(address, (struct in_addr *) host->h_addr_list[0], sizeof(struct in_addr));}static intcall_out(void){ int t; int sock; struct sockaddr_in address; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); exit(1); } t = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(t)); address.sin_family = AF_INET; address.sin_port = htons(Tunnel_Port); memset(&address.sin_zero, 0, sizeof(address.sin_zero)); find_host(Tunnel_Hostname, &address.sin_addr); if (connect(sock, (struct sockaddr *) &address, sizeof address)) { perror("connect"); exit(1); } return(sock);}static intanswer_call(void){ int t; int sock, conn; int addrlen; struct sockaddr_in address; sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); exit(1); } t = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(t)); address.sin_family = AF_INET; address.sin_port = htons(Tunnel_Port); address.sin_addr.s_addr = INADDR_ANY; memset(&address.sin_zero, 0, sizeof address.sin_zero); if (bind(sock, (struct sockaddr *) &address, sizeof address) < 0) { perror("bind"); exit(1); } if (listen(sock, 2) < 0) { perror("listen"); exit(1); } addrlen = sizeof address; conn = accept(sock, &address, &addrlen); if (conn < 0) { perror("accept"); exit(1); } close(sock); return(conn);}static voidopen_udp_sock(void){ int i; struct sockaddr_in address; Send_Sock = socket(AF_INET, SOCK_DGRAM, 0); if (Send_Sock < 0) { perror("socket"); exit(1); } for (i = 0; i < Num_Ports; i++) { Recv_Sock[i] = socket(AF_INET, SOCK_DGRAM, 0); if (Recv_Sock[i] < 0) { perror("socket"); exit(1); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; memset(&address.sin_zero, 0, sizeof address.sin_zero); address.sin_port = htons(Recv_Port[i]); if (bind(Recv_Sock[i], (struct sockaddr *) &address, sizeof address) < 0) { perror("bind"); exit(1); } }}static voidread_tcp(int sock, char *data, int len){ int off, r; for (off = 0; off < len; off += r) { r = read(sock, data + off, len - off); if (r <= 0) { perror("read"); exit(1); } }}static voidwrite_tcp(int sock, char *data, int len){ int off, r; for (off = 0; off < len; off += r) { r = write(sock, data + off, len - off); if (r <= 0) { perror("write"); exit(1); } }}static voidtunnel(void){ int i; int fdmax; fd_set fds; char buf[MAX_PACKET_SIZE]; short t; int len, port; struct sockaddr_in address; fdmax = Tunnel_Sock; for (i = 0; i < Num_Ports; i++) { if (Recv_Sock[i] > fdmax) { fdmax = Recv_Sock[i]; } } address.sin_family = AF_INET; if (Send_Hostname == NULL) { address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); } else { find_host(Send_Hostname, &address.sin_addr); } memset(&address.sin_zero, 0, sizeof address.sin_zero); while (1) { FD_ZERO(&fds); FD_SET(Tunnel_Sock, &fds); for (i = 0; i < Num_Ports; i++) { FD_SET(Recv_Sock[i], &fds); } if (select(fdmax + 1, &fds, NULL, NULL, NULL) < 0) { perror("select"); exit(1); } if (FD_ISSET(Tunnel_Sock, &fds)) { read_tcp(Tunnel_Sock, (char *) &t, sizeof (short)); len = ntohs(t); read_tcp(Tunnel_Sock, (char *) &t, sizeof (short)); port = ntohs(t); if (len > MAX_PACKET_SIZE) { fprintf(stderr, "packet too large: size = %x\n", len); exit(1); } if (port > Num_Ports) { fprintf(stderr, "port number too high: port = %d\n", port); exit(1); } read_tcp(Tunnel_Sock, buf, len); address.sin_port = htons(Send_Port[port]); if (sendto(Send_Sock, (void *) buf, len, 0, (struct sockaddr *) &address, sizeof address) < 0) { perror("sendto"); exit(1); } } for (i = 0; i < Num_Ports; i++) { if (FD_ISSET(Recv_Sock[i], &fds)) { len = recvfrom(Recv_Sock[i], buf, MAX_PACKET_SIZE, 0, NULL, 0); if (len < 0) { perror("recvfrom"); exit(1); } t = htons((short) len); write_tcp(Tunnel_Sock, (char *) &t, sizeof (short)); t = htons((short) i); write_tcp(Tunnel_Sock, (char *) &t, sizeof (short)); write_tcp(Tunnel_Sock, buf, len); } } }}intmain(int argc, char *argv[]){ int i, j; char rc; poptContext optCon; optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); rc = poptGetNextOpt(optCon); if (Send_Rtp_String != NULL) { int port_start, colons, is_number; port_start = 0; colons = 0; is_number = 1; for (i = 0; i < strlen(Send_Rtp_String); i++) { if (!isdigit(Send_Rtp_String[i])) { is_number = 0; } if (Send_Rtp_String[i] == ':') { if (colons == 0) { port_start = i + 1; } ++colons; } } if (colons > 1) { fprintf(stderr, "%s: -s argument %s has too many colons.\n", argv[0], Send_Rtp_String); exit(1); } if (is_number || colons == 1) { Send_Rtp_Port = strtol(Send_Rtp_String + port_start, NULL, 10); } if (!is_number) { Send_Hostname = Send_Rtp_String; if (colons == 1) { Send_Hostname[port_start - 1] = '\0'; } } } Num_Ports = 2; Recv_Port[0] = Recv_Rtp_Port; Recv_Port[1] = Recv_Rtp_Port + 1; Send_Port[0] = Send_Rtp_Port; Send_Port[1] = Send_Rtp_Port + 1; for (i = 0; i < Num_Ports; i++) { for (j = 0; j < Num_Ports; j++) { if (Recv_Port[i] == Send_Port[j] && Send_Hostname == NULL) { fprintf(stderr, "%s: Listening on and sending to UDP port %d. Bad!\n", argv[0], Recv_Port[i]); exit(1); } } } if (Tunnel_Hostname != NULL) { Tunnel_Sock = call_out(); } else { Tunnel_Sock = answer_call(); } open_udp_sock(); tunnel(); return 0;}/* * Local variables: * compile-command: "make -k rtptunnel" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -