~noskcaj/ubuntu/saucy/xinetd/2.3.15

« back to all changes in this revision

Viewing changes to xinetd/redirect.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Seyrat
  • Date: 2004-04-18 13:33:57 UTC
  • Revision ID: james.westby@ubuntu.com-20040418133357-czeqeju37433xvdd
Tags: upstream-2.3.13
ImportĀ upstreamĀ versionĀ 2.3.13

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
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 */
 
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, num_read, num_wrote=0, ret=0;
 
62
   unsigned int sin_len = 0;
 
63
   unsigned long bytes_in = 0, bytes_out = 0;
 
64
   int no_to_nagle = 1;
 
65
   int on = 1, v6on;
 
66
   char buff[NET_BUFFER];
 
67
   fd_set rdfd, msfd;
 
68
   struct timeval *timep = NULL;
 
69
   const char *func = "redir_handler";
 
70
   union xsockaddr serveraddr ;
 
71
 
 
72
   if( signal(SIGPIPE, redir_sigpipe) == SIG_ERR ) 
 
73
      msg(LOG_ERR, func, "unable to setup signal handler");
 
74
 
 
75
   close_all_svc_descriptors();
 
76
 
 
77
   /* If it's a tcp service we are redirecting */
 
78
   if( SC_PROTOVAL(scp) == IPPROTO_TCP )
 
79
   {
 
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);
 
87
      } else {
 
88
         msg(LOG_ERR, func, "not a valid protocol. Use IPv4 or IPv6.");
 
89
         exit(0);
 
90
      }
 
91
 
 
92
      if( RedirServerFd < 0 )
 
93
      {
 
94
         msg(LOG_ERR, func, "cannot create socket: %m");
 
95
         exit(0);
 
96
      }
 
97
 
 
98
      if( SC_IPV6( scp ) ) {
 
99
         if( SC_V6ONLY( scp ) ) {
 
100
            v6on = 1;
 
101
         } else {
 
102
            v6on = 0;
 
103
         }
 
104
#ifdef IPV6_V6ONLY
 
105
         if( setsockopt(RedirServerFd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6on, sizeof(v6on)) < 0 ) { 
 
106
            msg( LOG_ERR, func, "Setting IPV6_V6ONLY option failed (%m)" );
 
107
         }
 
108
#endif
 
109
 
 
110
      }
 
111
      if( SC_KEEPALIVE( scp ) )
 
112
         if (setsockopt(RedirServerFd, SOL_SOCKET, SO_KEEPALIVE, 
 
113
                        (char *)&on, sizeof( on ) ) < 0 )
 
114
            msg(LOG_ERR, func, 
 
115
                "setsockopt SO_KEEPALIVE RedirServerFd failed: %m");
 
116
      
 
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);
 
121
 
 
122
      if( connect(RedirServerFd, &serveraddr.sa, sin_len) < 0 )
 
123
      {
 
124
         msg(LOG_ERR, func, "can't connect to remote host %s: %m",
 
125
            xaddrname( &serveraddr ) );
 
126
         exit(0);
 
127
      }
 
128
 
 
129
      /* connection now established */
 
130
 
 
131
      if (setsockopt(RedirServerFd, IPPROTO_TCP, TCP_NODELAY, 
 
132
         (char *) &no_to_nagle, sizeof( on ) ) < 0) {
 
133
 
 
134
         msg(LOG_ERR, func, "setsockopt RedirServerFd failed: %m");
 
135
      }
 
136
 
 
137
      if (setsockopt(RedirDescrip, IPPROTO_TCP, TCP_NODELAY, 
 
138
         (char *) &no_to_nagle, sizeof( on ) ) < 0) {
 
139
 
 
140
         msg(LOG_ERR, func, "setsockopt RedirDescrip failed: %m");
 
141
      }
 
142
 
 
143
      maxfd = (RedirServerFd > RedirDescrip)?RedirServerFd:RedirDescrip;
 
144
      FD_ZERO(&msfd);
 
145
      FD_SET(RedirDescrip, &msfd);
 
146
      FD_SET(RedirServerFd, &msfd);
 
147
 
 
148
      while(1) {
 
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 */
 
152
            break;
 
153
         }
 
154
 
 
155
         if (FD_ISSET(RedirDescrip, &rdfd)) {
 
156
            do {
 
157
               num_read = read(RedirDescrip,
 
158
                  buff, sizeof(buff));
 
159
               if (num_read == -1 && errno == EINTR)
 
160
                  continue;
 
161
               if (num_read <= 0)
 
162
                  goto REDIROUT;
 
163
               bytes_in += num_read;
 
164
            } while (num_read < 0);
 
165
 
 
166
            /* Loop until we have written everything
 
167
             * that was read */
 
168
            num_wrote = 0;
 
169
            while( num_wrote < num_read ) {
 
170
               ret = write(RedirServerFd,
 
171
                  buff + num_wrote,
 
172
                  num_read - num_wrote);
 
173
               if (ret == -1 && errno == EINTR)
 
174
                  continue;
 
175
               if (ret <= 0)
 
176
                  goto REDIROUT;
 
177
               num_wrote += ret;
 
178
            }
 
179
         }
 
180
 
 
181
         if (FD_ISSET(RedirServerFd, &rdfd)) {
 
182
            do {
 
183
               num_read = read(RedirServerFd,
 
184
                  buff, sizeof(buff));
 
185
               if (num_read == -1 && errno == EINTR)
 
186
                  continue;
 
187
               if (num_read <= 0)
 
188
                  goto REDIROUT;
 
189
               bytes_out += num_read;
 
190
            } while (num_read < 0);
 
191
 
 
192
            /* Loop until we have written everything
 
193
             * that was read */
 
194
            num_wrote = 0;
 
195
            while( num_wrote < num_read ) {
 
196
               ret = write(RedirDescrip,
 
197
                  buff + num_wrote,
 
198
                  num_read - num_wrote);
 
199
               if (ret == -1 && errno == EINTR)
 
200
                  continue;
 
201
               if (ret <= 0)
 
202
                  goto REDIROUT;
 
203
               num_wrote += ret;
 
204
            }
 
205
         }
 
206
      }
 
207
REDIROUT:
 
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 );
 
211
      }
 
212
 
 
213
      exit(0);
 
214
   }
 
215
 
 
216
   msg(LOG_ERR, func, 
 
217
   "redirect with any protocol other than tcp is not supported at this time.");
 
218
   exit(0);
 
219
}