diff options
| author | Travis Bradshaw <travis.bradshaw@idsoftware.com> | 2012-01-31 14:32:09 -0600 |
|---|---|---|
| committer | Travis Bradshaw <travis.bradshaw@idsoftware.com> | 2012-01-31 14:32:09 -0600 |
| commit | 0023db327bc1db00068284b70e1db45857aeee35 (patch) | |
| tree | 01dd8366d20bd674741cfe8ceb069d82a2e33973 /QW/qwfwd/qwfwd.c | |
| download | quake-pum-0023db327bc1db00068284b70e1db45857aeee35.tar.gz | |
The Quake sources as originally release under the GPL license on December 21, 1999
Diffstat (limited to 'QW/qwfwd/qwfwd.c')
| -rw-r--r-- | QW/qwfwd/qwfwd.c | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/QW/qwfwd/qwfwd.c b/QW/qwfwd/qwfwd.c new file mode 100644 index 0000000..014d170 --- /dev/null +++ b/QW/qwfwd/qwfwd.c @@ -0,0 +1,269 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + + +/* + * udpred - a inetd launched udp port redirector + * + * Version: @(#)udpred.c 0.01 01/15/97 + * + * Author: Chris Faherty <chrisf@america.com> + * + * syntax: + * + * udpred toip toport + * + * sample inetd.conf entry: + * + * 7000 dgram udp wait root /usr/sbin/tcpd /usr/sbin/udpred 192.168.100.16 7000 + * + * + * 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. + * + */ +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdlib.h> +#include <sys/types.h> +#include <time.h> + +#ifdef _WIN32 +#include <winsock.h> +#else +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <netdb.h> +#include <netinet/in.h> +#include <unistd.h> +#include <syslog.h> + +#endif + +int host_port; // port we are listening on + +typedef struct peer { + time_t last; + struct sockaddr_in sin; + struct sockaddr_in dest; + int s; // connected socket to remote + struct peer *next; +} peer_t; + +peer_t *peers; + +/* +==================== +NET_Init +==================== +*/ +void NET_Init (void) +{ +#ifdef _WIN32 + static WSADATA winsockdata; +// WORD wVersionRequested; + int r; + +// wVersionRequested = MAKEWORD(1, 1); + + r = WSAStartup (MAKEWORD(2, 1), &winsockdata); + + if (r) { + fprintf(stderr, "Winsock initialization failed."); + exit(1); + } + + printf("Winsock Initialized\n"); +#endif +} + + + +int connectsock(char *host, char *service, char *protocol) +{ + struct hostent *phe; + struct servent *pse; + struct protoent *ppe; + struct sockaddr_in sin; + int s, type; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + +/* Map service name to port number */ + if(pse = getservbyname(service, protocol)) + sin.sin_port = pse->s_port; + else if((sin.sin_port = htons((u_short)atoi(service))) == 0) + { + fprintf(stderr, "udpred: can't get \"%s\" service entry\n", service); + exit(2); + } + +/* Map host name to IP address, allowing for dotted decimal */ + if(phe = gethostbyname(host)) + memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length); + else if((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) + { + fprintf(stderr, "udpred: can't get \"%s\" host entry\n", host); + exit(2); + } + +/* Map protocol name to protocol number */ + if((ppe = getprotobyname(protocol)) == 0) + { + fprintf(stderr, "udpred: can't get \"%s\" protocol entry\n", protocol); + exit(2); + } + +/* Use protocol to choose a socket type */ + if(strcmp(protocol, "udp") == 0) + type = SOCK_DGRAM; + else + type = SOCK_STREAM; + +/* Allocate a socket */ + s = socket(PF_INET, type, ppe->p_proto); + if(s < 0) + { + fprintf(stderr, "udpred: can't create socket: %s\n", sys_errlist[errno]); + exit(2); + } + +/* Connect the socket */ + if(connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) + { + fprintf(stderr, "udpred: can't connect to %s.%s: %s\n", host, service, sys_errlist[errno]); + exit(2); + } + return s; +} + +int main(int argc, char *argv[]) +{ + fd_set rfds; + struct timeval tv; + int retval; + int i1; + char buffer[4095]; + struct sockaddr_in fsin; + int alen; + peer_t *p; + int s; + struct sockaddr_in address; + + if (argc < 3) { + printf("Usage: %s <port> <remote server> <remote server port>\n", argv[0]); + return 1; + } + + NET_Init(); + + if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { + perror("socket"); + return 1; + } + + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons((unsigned short)atoi(argv[1])); + if (bind (s, (void *)&address, sizeof(address)) == -1) + perror("bind"); + + while(1) + { + FD_ZERO(&rfds); + FD_SET(s, &rfds); + i1 = s; + for (p = peers; p; p = p->next) { + FD_SET(p->s, &rfds); + if (p->s >= i1) + i1 = p->s + 1; + } + /* Wait up to two minutes. */ + tv.tv_sec = 2; + tv.tv_usec = 0; + retval = select(i1, &rfds, (fd_set *)0, (fd_set *)0, &tv); + if(retval > 0) + { + if(FD_ISSET(s, &rfds)) + { + alen = sizeof(fsin); + i1 = recvfrom(s, buffer, 4096, 0, (struct sockaddr *) &fsin, &alen); + if(i1 > 0) { + for (p = peers; p; p = p->next) + if (memcmp(&p->sin.sin_addr, &fsin.sin_addr, sizeof(p->sin.sin_addr)) == 0 && + memcmp(&p->sin.sin_port, &fsin.sin_port, sizeof(p->sin.sin_port)) == 0) + { + send(p->s, buffer, i1, 0); + time(&p->last); + break; + } + if (p == NULL) { // new peer + printf("peer %s:%d added", inet_ntoa(fsin.sin_addr), (int)ntohs(fsin.sin_port)); + p = malloc(sizeof *p); + p->sin = fsin; + p->s = connectsock(argv[2], argv[3], "udp"); + p->next = peers; + peers = p; + send(p->s, buffer, i1, 0); + time(&p->last); + } + } + } + for (p = peers; p; p = p->next) + if(FD_ISSET(p->s, &rfds)) + { + i1 = recv(p->s, buffer, 4096, 0); + if(i1 > 0) { + time(&p->last); + sendto(s, buffer, i1, 0, (struct sockaddr *) &p->sin, + sizeof(p->sin)); + } + } + } else { + peer_t *pp; + + pp = NULL; + p = peers; + while (p) { + if (time(NULL) - p->last > 300) { + if (!pp && !p->next) { + printf("peer %s:%d removed (timeout)", inet_ntoa(p->sin.sin_addr), (int)ntohs(p->sin.sin_port)); + free(p); + p = pp = NULL; + continue; + } + pp->next = p->next; + printf ("peer %s:%d removed (timeout)", inet_ntoa(p->sin.sin_addr), (int)ntohs(p->sin.sin_port)); + free(p); + p = pp->next; + } else { + pp = p; + p = p->next; + } + } + } + } +} |
