2 * (c) Copyright 1998-2001 by Rob Braun
3 * All rights reserved. The file named COPYRIGHT specifies the terms
4 * and conditions for redistribution.
8 #include <sys/socket.h>
10 #ifdef HAVE_SYS_RESOURCE_H
11 #include <sys/resource.h>
14 #include <netinet/in.h>
23 #include <netinet/tcp.h>
24 #ifdef HAVE_ARPA_INET_H
25 #include <arpa/inet.h>
27 #ifdef HAVE_SYS_SIGNAL_H
28 #include <sys/signal.h>
37 #define NET_BUFFER 1500
39 static int RedirServerFd = -1;
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.
46 __attribute__ ((noreturn))
48 static void redir_sigpipe( int signum )
50 Sclose(RedirServerFd);
54 /* Do the redirection of a service */
55 /* This function gets called from child.c after we have been forked */
56 void redir_handler( struct server *serp )
58 struct service *sp = SERVER_SERVICE( serp );
59 struct service_config *scp = SVC_CONF( sp );
60 int RedirDescrip = SERVER_FD( serp );
61 int maxfd, num_read, num_wrote=0, ret=0;
62 unsigned int sin_len = 0;
63 unsigned long bytes_in = 0, bytes_out = 0;
66 char buff[NET_BUFFER];
68 struct timeval *timep = NULL;
69 const char *func = "redir_handler";
70 union xsockaddr serveraddr ;
72 if( signal(SIGPIPE, redir_sigpipe) == SIG_ERR )
73 msg(LOG_ERR, func, "unable to setup signal handler");
75 close_all_svc_descriptors();
77 /* If it's a tcp service we are redirecting */
78 if( SC_PROTOVAL(scp) == IPPROTO_TCP )
80 memcpy(&serveraddr, SC_REDIR_ADDR(scp), sizeof(serveraddr));
81 if( serveraddr.sa_in.sin_family == AF_INET ) {
82 sin_len = sizeof( struct sockaddr_in );
83 RedirServerFd = socket(AF_INET, SOCK_STREAM, 0);
84 } else if( serveraddr.sa_in.sin_family == AF_INET6 ) {
85 sin_len = sizeof( struct sockaddr_in6 );
86 RedirServerFd = socket(AF_INET6, SOCK_STREAM, 0);
88 msg(LOG_ERR, func, "not a valid protocol. Use IPv4 or IPv6.");
92 if( RedirServerFd < 0 )
94 msg(LOG_ERR, func, "cannot create socket: %m");
98 if( SC_IPV6( scp ) ) {
99 if( SC_V6ONLY( scp ) ) {
105 if( setsockopt(RedirServerFd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6on, sizeof(v6on)) < 0 ) {
106 msg( LOG_ERR, func, "Setting IPV6_V6ONLY option failed (%m)" );
111 if( SC_KEEPALIVE( scp ) )
112 if (setsockopt(RedirServerFd, SOL_SOCKET, SO_KEEPALIVE,
113 (char *)&on, sizeof( on ) ) < 0 )
115 "setsockopt SO_KEEPALIVE RedirServerFd failed: %m");
117 if( serveraddr.sa_in.sin_family == AF_INET )
118 serveraddr.sa_in.sin_port = htons(serveraddr.sa_in.sin_port);
119 if( serveraddr.sa_in.sin_family == AF_INET6 )
120 serveraddr.sa_in6.sin6_port = htons(serveraddr.sa_in6.sin6_port);
122 if( connect(RedirServerFd, &serveraddr.sa, sin_len) < 0 )
124 msg(LOG_ERR, func, "can't connect to remote host %s: %m",
125 xaddrname( &serveraddr ) );
129 /* connection now established */
131 if (setsockopt(RedirServerFd, IPPROTO_TCP, TCP_NODELAY,
132 (char *) &no_to_nagle, sizeof( on ) ) < 0) {
134 msg(LOG_ERR, func, "setsockopt RedirServerFd failed: %m");
137 if (setsockopt(RedirDescrip, IPPROTO_TCP, TCP_NODELAY,
138 (char *) &no_to_nagle, sizeof( on ) ) < 0) {
140 msg(LOG_ERR, func, "setsockopt RedirDescrip failed: %m");
143 maxfd = (RedirServerFd > RedirDescrip)?RedirServerFd:RedirDescrip;
145 FD_SET(RedirDescrip, &msfd);
146 FD_SET(RedirServerFd, &msfd);
149 memcpy(&rdfd, &msfd, sizeof(rdfd));
150 if (select(maxfd + 1, &rdfd, (fd_set *)0, (fd_set *)0, timep) <= 0) {
151 /* place for timeout code, currently does not time out */
155 if (FD_ISSET(RedirDescrip, &rdfd)) {
157 num_read = read(RedirDescrip,
159 if (num_read == -1 && errno == EINTR)
163 bytes_in += num_read;
164 } while (num_read < 0);
166 /* Loop until we have written everything
169 while( num_wrote < num_read ) {
170 ret = write(RedirServerFd,
172 num_read - num_wrote);
173 if (ret == -1 && errno == EINTR)
181 if (FD_ISSET(RedirServerFd, &rdfd)) {
183 num_read = read(RedirServerFd,
185 if (num_read == -1 && errno == EINTR)
189 bytes_out += num_read;
190 } while (num_read < 0);
192 /* Loop until we have written everything
195 while( num_wrote < num_read ) {
196 ret = write(RedirDescrip,
198 num_read - num_wrote);
199 if (ret == -1 && errno == EINTR)
208 if( M_IS_SET( SC_LOG_ON_SUCCESS(scp), LO_TRAFFIC ) ) {
209 svc_logprint( SERVER_CONNSERVICE( serp ), "TRAFFIC",
210 "in=%lu(bytes) out=%lu(bytes)", bytes_in, bytes_out );
217 "redirect with any protocol other than tcp is not supported at this time.");