1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20
21
22/*
23 * udpred - a inetd launched udp port redirector
24 *
25 * Version:	@(#)udpred.c 0.01   01/15/97
26 *
27 * Author:	Chris Faherty <chrisf@america.com>
28 *
29 * syntax:
30 *
31 * udpred toip toport
32 *
33 * sample inetd.conf entry:
34 *
35 * 7000	dgram	udp	wait	root	/usr/sbin/tcpd	/usr/sbin/udpred 192.168.100.16 7000
36 *
37 *
38 *	This program is free software; you can redistribute it and/or
39 *	modify it under the terms of the GNU General Public License
40 *	as published by the Free Software Foundation; either version
41 *	2 of the License, or (at your option) any later version.
42 *
43 */
44#include <stdio.h>
45#include <errno.h>
46#include <fcntl.h>
47#include <signal.h>
48#include <stdlib.h>
49#include <sys/types.h>
50#include <time.h>
51
52#ifdef _WIN32
53#include <winsock.h>
54#else
55#include <sys/time.h>
56#include <sys/socket.h>
57#include <sys/wait.h>
58#include <netdb.h>
59#include <netinet/in.h>
60#include <unistd.h>
61#include <syslog.h>
62
63#endif
64
65int host_port; // port we are listening on
66
67typedef struct peer {
68	time_t last;
69	struct sockaddr_in sin;
70	struct sockaddr_in dest;
71	int s; // connected socket to remote
72	struct peer *next;
73} peer_t;
74
75peer_t *peers;
76
77/*
78====================
79NET_Init
80====================
81*/
82void NET_Init (void)
83{
84#ifdef _WIN32
85	static WSADATA          winsockdata;
86//    WORD    wVersionRequested;
87    int             r;
88
89//    wVersionRequested = MAKEWORD(1, 1);
90
91    r = WSAStartup (MAKEWORD(2, 1), &winsockdata);
92
93    if (r) {
94		fprintf(stderr, "Winsock initialization failed.");
95		exit(1);
96	}
97
98    printf("Winsock Initialized\n");
99#endif
100}
101
102
103
104int connectsock(char *host, char *service, char *protocol)
105{
106	struct hostent *phe;
107	struct servent *pse;
108	struct protoent *ppe;
109	struct sockaddr_in sin;
110	int s, type;
111
112	memset(&sin, 0, sizeof(sin));
113	sin.sin_family = AF_INET;
114
115/* Map service name to port number */
116	if(pse = getservbyname(service, protocol))
117		sin.sin_port = pse->s_port;
118	else if((sin.sin_port = htons((u_short)atoi(service))) == 0)
119	{
120		fprintf(stderr, "udpred: can't get \"%s\" service entry\n", service);
121		exit(2);
122	}
123
124/* Map host name to IP address, allowing for dotted decimal */
125	if(phe = gethostbyname(host))
126		memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length);
127	else if((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE)
128	{
129		fprintf(stderr, "udpred: can't get \"%s\" host entry\n", host);
130		exit(2);
131	}
132
133/* Map protocol name to protocol number */
134	if((ppe = getprotobyname(protocol)) == 0)
135	{
136		fprintf(stderr, "udpred: can't get \"%s\" protocol entry\n", protocol);
137		exit(2);
138	}
139
140/* Use protocol to choose a socket type */
141	if(strcmp(protocol, "udp") == 0)
142		type = SOCK_DGRAM;
143	else
144		type = SOCK_STREAM;
145
146/* Allocate a socket */
147	s = socket(PF_INET, type, ppe->p_proto);
148	if(s < 0)
149	{
150		fprintf(stderr, "udpred: can't create socket: %s\n", sys_errlist[errno]);
151		exit(2);
152	}
153
154/* Connect the socket */
155	if(connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
156	{
157		fprintf(stderr, "udpred: can't connect to %s.%s: %s\n", host, service, sys_errlist[errno]);
158		exit(2);
159	}
160	return s;
161}
162
163int main(int argc, char *argv[])
164{
165	fd_set rfds;
166	struct timeval tv;
167	int retval;
168	int i1;
169	char buffer[4095];
170	struct sockaddr_in fsin;
171	int alen;
172	peer_t *p;
173	int s;
174	struct sockaddr_in	address;
175
176	if (argc < 3) {
177		printf("Usage:  %s <port> <remote server> <remote server port>\n", argv[0]);
178		return 1;
179	}
180
181	NET_Init();
182
183	if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
184		perror("socket");
185		return 1;
186	}
187
188	address.sin_family = AF_INET;
189	address.sin_addr.s_addr = INADDR_ANY;
190	address.sin_port = htons((unsigned short)atoi(argv[1]));
191	if (bind (s, (void *)&address, sizeof(address)) == -1)
192		perror("bind");
193
194	while(1)
195	{
196		FD_ZERO(&rfds);
197		FD_SET(s, &rfds);
198		i1 = s;
199		for (p = peers; p; p = p->next) {
200			FD_SET(p->s, &rfds);
201			if (p->s >= i1)
202				i1 = p->s + 1;
203		}
204		/* Wait up to two minutes. */
205		tv.tv_sec = 2;
206		tv.tv_usec = 0;
207		retval = select(i1, &rfds, (fd_set *)0, (fd_set *)0, &tv);
208		if(retval > 0)
209		{
210			if(FD_ISSET(s, &rfds))
211			{
212				alen = sizeof(fsin);
213				i1 = recvfrom(s, buffer, 4096, 0, (struct sockaddr *) &fsin, &alen);
214				if(i1 > 0) {
215					for (p = peers; p; p = p->next)
216						if (memcmp(&p->sin.sin_addr, &fsin.sin_addr, sizeof(p->sin.sin_addr)) == 0 &&
217							memcmp(&p->sin.sin_port, &fsin.sin_port, sizeof(p->sin.sin_port)) == 0)
218						{
219							send(p->s, buffer, i1, 0);
220							time(&p->last);
221							break;
222						}
223					if (p == NULL) { // new peer
224						printf("peer %s:%d added", inet_ntoa(fsin.sin_addr), (int)ntohs(fsin.sin_port));
225						p = malloc(sizeof *p);
226						p->sin = fsin;
227						p->s = connectsock(argv[2], argv[3], "udp");
228						p->next = peers;
229						peers = p;
230						send(p->s, buffer, i1, 0);
231						time(&p->last);
232					}
233				}
234			}
235			for (p = peers; p; p = p->next)
236				if(FD_ISSET(p->s, &rfds))
237				{
238					i1 = recv(p->s, buffer, 4096, 0);
239					if(i1 > 0) {
240						time(&p->last);
241						sendto(s, buffer, i1, 0, (struct sockaddr *) &p->sin,
242							sizeof(p->sin));
243					}
244				}
245		} else {
246			peer_t *pp;
247
248			pp = NULL;
249			p = peers;
250			while (p) {
251				if (time(NULL) - p->last > 300) {
252					if (!pp && !p->next) {
253						printf("peer %s:%d removed (timeout)", inet_ntoa(p->sin.sin_addr), (int)ntohs(p->sin.sin_port));
254						free(p);
255						p = pp = NULL;
256						continue;
257					}
258					pp->next = p->next;
259					printf ("peer %s:%d removed (timeout)", inet_ntoa(p->sin.sin_addr), (int)ntohs(p->sin.sin_port));
260					free(p);
261					p = pp->next;
262				} else {
263					pp = p;
264					p = p->next;
265				}
266			}
267		}
268	}
269}
270