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