1 /*
2  * (c) Copyright 1998-2001 by Rob Braun
3  * All rights reserved.  The file named COPYRIGHT specifies the terms
4  * and conditions for redistribution.
5  */
6 #include "config.h"
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <sys/time.h>
10 #ifdef HAVE_SYS_RESOURCE_H
11 #include <sys/resource.h>
12 #endif
13 #include <sys/wait.h>
14 #include <netinet/in.h>
15 #include <errno.h>
16 #include <pwd.h>
17 #include <fcntl.h>
18 #include <stdio.h>
19 #include <sys/wait.h>
20 #include <signal.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <netinet/tcp.h>
24 #ifdef HAVE_ARPA_INET_H
25 #include <arpa/inet.h>
26 #endif
27 #ifdef HAVE_SYS_SIGNAL_H
28 #include <sys/signal.h>
29 #endif
30 
31 #include "redirect.h"
32 #include "service.h"
33 #include "log.h"
34 #include "sconf.h"
35 #include "msg.h"
36 
37 #define NET_BUFFER 1500
38 
39 static int RedirServerFd = -1;
40 
41 /* Theoretically, this gets invoked when the remote side is no
42  * longer available for reading or writing.
43  * So, we send a HUP to the child process, wait(), then exit.
44  */
45 #ifdef __GNUC__
46 __attribute__ ((noreturn))
47 #endif
redir_sigpipe(int signum)48 static void redir_sigpipe( int signum )
49 {
50    Sclose(RedirServerFd);
51    _exit(0);
52 }
53 
54 /* Do the redirection of a service */
55 /* This function gets called from child.c after we have been forked */
redir_handler(struct server * serp)56 void redir_handler( struct server *serp )
57 {
58    struct service *sp = SERVER_SERVICE( serp );
59    struct service_config *scp = SVC_CONF( sp );
60    int RedirDescrip = SERVER_FD( serp );
61    int maxfd;
62    ssize_t num_read, num_wrote=0, ret=0;
63    unsigned int sin_len = 0;
64    unsigned long bytes_in = 0, bytes_out = 0;
65    int no_to_nagle = 1;
66    int on = 1, v6on;
67    char buff[NET_BUFFER];
68    fd_set rdfd, msfd;
69    struct timeval *timep = NULL;
70    const char *func = "redir_handler";
71    union xsockaddr serveraddr ;
72 
73    if( signal(SIGPIPE, redir_sigpipe) == SIG_ERR )
74       msg(LOG_ERR, func, "unable to setup signal handler");
75 
76    close_all_svc_descriptors();
77 
78    /* If it's a tcp service we are redirecting */
79    if( SC_PROTOVAL(scp) == IPPROTO_TCP )
80    {
81       memcpy(&serveraddr, SC_REDIR_ADDR(scp), sizeof(serveraddr));
82       if( serveraddr.sa_in.sin_family == AF_INET ) {
83          sin_len = sizeof( struct sockaddr_in );
84          RedirServerFd = socket(AF_INET, SOCK_STREAM, 0);
85        } else if( serveraddr.sa_in.sin_family == AF_INET6 ) {
86          sin_len = sizeof( struct sockaddr_in6 );
87          RedirServerFd = socket(AF_INET6, SOCK_STREAM, 0);
88       } else {
89          msg(LOG_ERR, func, "not a valid protocol. Use IPv4 or IPv6.");
90          exit(0);
91       }
92 
93       if( RedirServerFd < 0 )
94       {
95          msg(LOG_ERR, func, "cannot create socket: %m");
96          exit(0);
97       }
98 
99       if( SC_IPV6( scp ) ) {
100          if( SC_V6ONLY( scp ) ) {
101             v6on = 1;
102          } else {
103             v6on = 0;
104          }
105 #ifdef IPV6_V6ONLY
106          if( setsockopt(RedirServerFd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6on, sizeof(v6on)) < 0 ) {
107             msg( LOG_ERR, func, "Setting IPV6_V6ONLY option failed (%m)" );
108          }
109 #endif
110 
111       }
112       if( SC_KEEPALIVE( scp ) )
113          if (setsockopt(RedirServerFd, SOL_SOCKET, SO_KEEPALIVE,
114                         (char *)&on, sizeof( on ) ) < 0 )
115             msg(LOG_ERR, func,
116                 "setsockopt SO_KEEPALIVE RedirServerFd failed: %m");
117 
118       if( serveraddr.sa_in.sin_family == AF_INET )
119          serveraddr.sa_in.sin_port = htons(serveraddr.sa_in.sin_port);
120       if( serveraddr.sa_in.sin_family == AF_INET6 )
121          serveraddr.sa_in6.sin6_port = htons(serveraddr.sa_in6.sin6_port);
122 
123       if( connect(RedirServerFd, &serveraddr.sa, sin_len) < 0 )
124       {
125          msg(LOG_ERR, func, "can't connect to remote host %s: %m",
126             xaddrname( &serveraddr ) );
127          exit(0);
128       }
129 
130       /* connection now established */
131 
132       if (setsockopt(RedirServerFd, IPPROTO_TCP, TCP_NODELAY,
133          (char *) &no_to_nagle, sizeof( on ) ) < 0) {
134 
135          msg(LOG_ERR, func, "setsockopt RedirServerFd failed: %m");
136       }
137 
138       if (setsockopt(RedirDescrip, IPPROTO_TCP, TCP_NODELAY,
139          (char *) &no_to_nagle, sizeof( on ) ) < 0) {
140 
141          msg(LOG_ERR, func, "setsockopt RedirDescrip failed: %m");
142       }
143 
144       maxfd = (RedirServerFd > RedirDescrip)?RedirServerFd:RedirDescrip;
145       FD_ZERO(&msfd);
146       FD_SET(RedirDescrip, &msfd);
147       FD_SET(RedirServerFd, &msfd);
148 
149       while(1) {
150          memcpy(&rdfd, &msfd, sizeof(rdfd));
151          if (select(maxfd + 1, &rdfd, (fd_set *)0, (fd_set *)0, timep) <= 0) {
152             /* place for timeout code, currently does not time out */
153             break;
154          }
155 
156          if (FD_ISSET(RedirDescrip, &rdfd)) {
157             do {
158                num_read = read(RedirDescrip,
159                   buff, sizeof(buff));
160                if (num_read == (ssize_t)-1 && errno == EINTR)
161                   continue;
162                if (num_read <= 0)
163                   goto REDIROUT;
164                bytes_in += num_read;
165             } while (num_read < 0);
166 
167             /* Loop until we have written everything
168              * that was read */
169             num_wrote = 0;
170             while( num_wrote < num_read ) {
171                ret = write(RedirServerFd,
172                   buff + num_wrote,
173                   num_read - num_wrote);
174                if (ret == -1 && errno == EINTR)
175                   continue;
176                if (ret <= 0)
177                   goto REDIROUT;
178                num_wrote += ret;
179             }
180          }
181 
182          if (FD_ISSET(RedirServerFd, &rdfd)) {
183             do {
184                num_read = read(RedirServerFd,
185                   buff, sizeof(buff));
186                if (num_read == -1 && errno == EINTR)
187                   continue;
188                if (num_read <= 0)
189                   goto REDIROUT;
190                bytes_out += num_read;
191             } while (num_read < 0);
192 
193             /* Loop until we have written everything
194              * that was read */
195             num_wrote = 0;
196             while( num_wrote < num_read ) {
197                ret = write(RedirDescrip,
198                   buff + num_wrote,
199                   num_read - num_wrote);
200                if (ret == -1 && errno == EINTR)
201                   continue;
202                if (ret <= 0)
203                   goto REDIROUT;
204                num_wrote += ret;
205             }
206          }
207       }
208 REDIROUT:
209       if( M_IS_SET( SC_LOG_ON_SUCCESS(scp), LO_TRAFFIC ) ) {
210          svc_logprint( SERVER_CONNSERVICE( serp ), "TRAFFIC",
211                        "in=%lu(bytes) out=%lu(bytes)", bytes_in, bytes_out );
212       }
213 
214       exit(0);
215    }
216 
217    msg(LOG_ERR, func,
218    "redirect with any protocol other than tcp is not supported at this time.");
219    exit(0);
220 }
221