1 /*
2  *  Copyright (C) 1995, 1996  Karl-Johan Johnsson.
3  */
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <signal.h>
10 #include <errno.h>
11 #include <sys/time.h>
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <netdb.h>
16 #include <sys/wait.h>
17 
18 #undef  False
19 #define False 0
20 #undef  True
21 #define True  1
22 
23 #define DEFAULT_REMOTE_PORT	119
24 
25 /*
26  *  Define this if <unistd.h> doesn't declare getopt() and friends.
27  */
28 #define BOGUS_UNISTD
29 
perror_exit(const char * msg)30 static void perror_exit(const char *msg)
31 {
32     perror(msg);
33     _exit(1);
34 }
35 
xrealloc(void * ptr,size_t size)36 static void* xrealloc(void *ptr, size_t size)
37 {
38     if (!ptr)
39 	ptr = malloc(size); /* Hack for broken C libraries */
40     else
41 	ptr = realloc(ptr, size);
42 
43     if (!ptr)
44 	perror_exit("malloc");
45 
46     return ptr;
47 }
48 
49 static struct in_addr	*allowed_hosts = NULL;
50 static long		 n_hosts       = 0;
51 static long		 n_alloced     = 0;
52 
allow_host(char * host)53 static void allow_host(char *host)
54 {
55     struct hostent	*hent;
56 
57     hent = gethostbyname(host);
58     if (!hent) {
59 	fprintf(stderr, "No such host: %s\n", host);
60 	return;
61     }
62 
63     if (n_hosts >= n_alloced)
64 	allowed_hosts = xrealloc(allowed_hosts,
65 				 (n_alloced = 2 * (n_alloced + 1)) *
66 				 sizeof allowed_hosts[0]);
67 
68     memcpy(&allowed_hosts[n_hosts++], hent->h_addr, hent->h_length);
69 }
70 
is_allowed(struct sockaddr_in * addr)71 static int is_allowed(struct sockaddr_in *addr)
72 {
73     long	i;
74 
75     for (i = 0 ; i < n_hosts ; i++)
76 	if (memcmp(&addr->sin_addr, &allowed_hosts[i],
77 		   sizeof addr->sin_addr) == 0)
78 	    return True;
79 
80     return False;
81 }
82 
get_remote_host(char * host)83 static struct sockaddr_in get_remote_host(char *host)
84 {
85     struct sockaddr_in	addr;
86     struct hostent	*hent;
87     char		*c;
88 
89     memset(&addr, 0, sizeof addr);
90     addr.sin_family = PF_INET;
91     addr.sin_port   = htons(DEFAULT_REMOTE_PORT);
92     c = strchr(host, ':');
93     if (c) {
94 	*c++ = '\0';
95 	/* FIXME: error check? */
96 	addr.sin_port = htons(atoi(c));
97     }
98 
99     hent = gethostbyname(host);
100     if (!hent) {
101 	fprintf(stderr, "No such host: %s\n", host);
102 	_exit(1);
103     }
104 
105     memcpy(&addr.sin_addr, hent->h_addr, hent->h_length);
106 
107     return addr;
108 }
109 
do_rw(int from,int to)110 static int do_rw(int from, int to)
111 {
112     static char buffer[16384];
113     char	*c;
114     long	i, j, n;
115 
116     do {
117 	n = read(from, buffer, sizeof buffer);
118     } while (n < 0 && errno == EINTR);
119 
120     c = buffer;
121     i = n;
122     while (i > 0) {
123 	j = write(to, c, i);
124 	if (j < 0)
125 	    if (errno == EINTR)
126 		continue;
127 	    else
128 		return -1;
129 	if (j == 0)
130 	    return 0;
131 	c += j;
132 	i -= j;
133     }
134 
135     return n;
136 }
137 
open_serv_socket(struct sockaddr_in * serv_addr)138 static int open_serv_socket(struct sockaddr_in *serv_addr)
139 {
140     int	ss, tmp;
141 
142     ss = socket(PF_INET, SOCK_STREAM, 0);
143     if (ss < 0)
144 	return -1;
145 
146     do {
147 	tmp = connect(ss, (struct sockaddr *)serv_addr, sizeof *serv_addr);
148     } while (tmp < 0 && errno == EINTR);
149 
150     if (tmp < 0) {
151 	perror("connect");
152 	close(ss);
153 	return -1;
154     }
155 
156     return ss;
157 }
158 
child(struct sockaddr_in * serv_addr,int cs)159 static int child(struct sockaddr_in *serv_addr, int cs)
160 {
161     fd_set	fds;
162     int		max, ss, tmp = 0;
163 
164     ss = open_serv_socket(serv_addr);
165     if (ss < 0)
166 	return -1;
167 
168     FD_ZERO(&fds);
169     FD_SET(cs, &fds);
170     FD_SET(ss, &fds);
171     max = (cs > ss ? cs : ss) + 1;
172 
173     for (;;) {
174 	fd_set	rd_fds = fds;
175 
176 	tmp = select(max, &rd_fds, NULL, NULL, NULL);
177 	if (tmp < 0)
178 	    if (errno == EINTR)
179 		continue;
180 	    else
181 		break;
182 
183 	if (FD_ISSET(cs, &rd_fds)) {
184 	    tmp = do_rw(cs, ss);
185 	    if (tmp <= 0)
186 		break;
187 	}
188 
189 	if (FD_ISSET(ss, &rd_fds)) {
190 	    tmp = do_rw(ss, cs);
191 	    if (tmp <= 0)
192 		break;
193 	}
194     }
195 
196     if (tmp < 0)
197 	perror("read/write");
198 
199     close(ss);
200 
201     return tmp;
202 }
203 
doit(struct sockaddr_in * serv_addr,int port,int single)204 static void doit(struct sockaddr_in *serv_addr, int port, int single)
205 {
206     struct sockaddr_in	local_addr, cli_addr;
207     int			as;
208     int			yes = 1;
209 
210     memset(&local_addr, 0, sizeof local_addr);
211     local_addr.sin_family = PF_INET;
212     local_addr.sin_port = port;
213 
214     as = socket(PF_INET, SOCK_STREAM, 0);
215     if (as < 0)
216 	perror_exit("socket");
217     if (setsockopt(as, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof yes) < 0)
218 	perror_exit("setsockopt(SO_REUSEADDR)");
219     if (bind(as, (struct sockaddr *)&local_addr, sizeof local_addr) < 0)
220 	perror_exit("bind");
221     if (listen(as, 5) < 0)
222 	perror_exit("listen");
223 
224     for (;;) {
225 	int	cs, len;
226 
227 	do {
228 	    len = sizeof cli_addr;
229 	    cs = accept(as, (struct sockaddr *)&cli_addr, &len);
230 	} while (cs < 0 && errno == EINTR);
231 
232 	if (cs < 0)
233 	    perror_exit("accept");
234 
235 	if (!is_allowed(&cli_addr)) {
236 	    static char deny[] = "502 You have no permission to talk!\r\n";
237 
238 	    if (serv_addr->sin_port == htons(119))
239 		write(cs, deny, sizeof deny - 1);
240 	    shutdown(cs, 2);
241 	    close(cs);
242 	    continue;
243 	}
244 
245 	if (single)
246 	    child(serv_addr, cs);
247 	else
248 	    switch (fork()) {
249 	    case -1:
250 		perror_exit("fork");
251 		break;
252 	    case 0:
253 		if (child(serv_addr, cs) < 0)
254 		    _exit(1);
255 		_exit(0);
256 	    default:
257 		break;
258 	    }
259 
260 	close(cs);
261     }
262 }
263 
264 /************************************************************************/
265 
sig_chld(int no)266 static void sig_chld(int no)
267 {
268     while (waitpid(-1, NULL, WNOHANG) > 0);
269 }
270 
install_sig_handlers(void)271 static void install_sig_handlers(void)
272 {
273     struct sigaction	sig_act;
274 
275     sig_act.sa_handler = sig_chld;
276     sig_act.sa_flags   = 0;
277     sigfillset(&sig_act.sa_mask);
278     if (sigaction(SIGCHLD, &sig_act, NULL) < 0)
279 	perror_exit("sigaction(SIGCHLD)");
280 
281     sig_act.sa_handler = SIG_IGN;
282     sig_act.sa_flags = 0;
283     sigemptyset(&sig_act.sa_mask);
284     if (sigaction(SIGPIPE, &sig_act, NULL) < 0)
285 	perror_exit("sigaction(SIGPIPE)");
286 }
287 
usage(char * name)288 static void usage(char *name)
289 {
290     fprintf(stderr, "Usage: %s -p port [-s] -h host [...] remotehost:port\n",
291 	    name);
292     _exit(1);
293 }
294 
main(int argc,char * argv[])295 int main(int argc, char *argv[])
296 {
297     struct sockaddr_in	serv_addr;
298     int			single = False;
299     int			port = 0;
300     int			c;
301 #ifdef BOGUS_UNISTD
302     extern int	 getopt(int, char *const[], const char*);
303     extern char	*optarg;
304     extern int	 optind, opterr;
305 #endif
306 
307     freopen("/dev/null", "r", stdin);
308     freopen("/dev/null", "w", stdout);
309 
310     install_sig_handlers();
311 
312     opterr = 0;
313     while ((c = getopt(argc, argv, "p:h:s")) != -1)
314 	switch (c) {
315 	case 'p': /* port to listen on */
316 	    if (sscanf(optarg, "%d", &port) != 1 || port < 0)
317 		usage(argv[0]);
318 	    port = htons(port);
319 	    break;
320 	case 's':
321 	    single = True;
322 	    break;
323 	case 'h':
324 	    allow_host(optarg);
325 	    break;
326 	default:
327 	    usage(argv[0]);
328 	    break;
329 	}
330 
331     if (optind != argc - 1 || port == 0)
332 	usage(argv[0]);
333 
334     if (n_hosts <= 0) {
335 	fprintf(stderr, "No allowed hosts!\n");
336 	_exit(1);
337     }
338 
339     serv_addr = get_remote_host(argv[optind]);
340     doit(&serv_addr, port, single);
341 
342     return 0;
343 }
344