[You forgot to cc: the list]
On Fri, Jan 11, 2008 at 03:24:32PM -0500, Alan Pinstein wrote:
On Jan 11, 2008, at 3:02 PM, Luis Rodrigo Gallardo Cruz wrote:
On Fri, Jan 11, 2008 at 02:31:58PM -0500, Alan Pinstein wrote:
Hi All- [ Stunnel listens on ports it shouldn't ]
If I start up stunnel from the command line as "root" or another user even, it only listens on the port listed in the conf file.
Could you have some startup script that's automatically getting run with your logrotate scripts?
The problem happens the MOMENT stunnel starts. It has nothing to do with the logrotate scripts.
Oh, sorry, I got confused. (/me goes and re-reads the original mail ...)
I've done a bunch of debugging and can't figure out what's going on. I have only one guess: stunnel automatically listens on any ports that the process calling stunnel is listening on, in some sort of attempt to seamlessly add SSL to existing daemons. I can't find any docs or tell from the source code, but it's the only idea I can't rule out...
All this is in a *nix, right?
The following is an educated guess:
Open connections are open file descriptors, and fork()/exec() do not close open file descriptors. Thus, stunnel is inheriting the open connection. And, since it knows nothing about it, it does not close it or anything like that. So it's not that it activelly listens on it, but only that it does not bother to stop. You might check this theory by trying to connect to the port *after* apache is shut down. If I'm right you should get no answer at all.
So, the solution is to have the file descriptors close when exec'ing stunnel. PHP or apache might have some option somewhere to do that (look for "close on exec" or something similarly named), but if not, you might have to write some sort of wrapper to do it. It's a messy thing, because AFAIK there's no clean way to do it short of
for (i = 0; i < [some-hopefuly-large-enough-value]; i++) close(i);
where the [large-enough-value] is determined by your system's file descriptor limit and your desire not to loop all the way to 2^32 or something.
[You forgot to cc: the list]
Oops sorry thanks... my other lists do that automatically :)
All this is in a *nix, right?
Yes. RHEL5.
The following is an educated guess:
Open connections are open file descriptors, and fork()/exec() do not close open file descriptors. Thus, stunnel is inheriting the open connection. And, since it knows nothing about it, it does not close it or anything like that. So it's not that it activelly listens on it, but only that it does not bother to stop. You might check this theory by trying to connect to the port *after* apache is shut down. If I'm right you should get no answer at all.
I don't know a lot about sockets programming, but I am not sure this makes sense... I don't WANT stunnel to stop listening to those ports; rather it shouldn't ever start. stunnel has a config file, so I'd expect it to only listen to the ports it was told to listen to, which is 4449.
I run lots of child processes from php and none of them end up listening to port 80/443 once the server exits.
Although, now that I think about it, I am not sure I daemonize any processes from a php script...
But still I think that stunnel is actively listening on these ports. Forked processed just don't inherit sockets from parents AFAIK....
So, the solution is to have the file descriptors close when exec'ing stunnel. PHP or apache might have some option somewhere to do that (look for "close on exec" or something similarly named), but if not, you might have to write some sort of wrapper to do it. It's a messy thing, because AFAIK there's no clean way to do it short of
for (i = 0; i < [some-hopefuly-large-enough-value]; i++) close(i);
Yeah that couldn't be a good idea...
I am open to using stunnel in a different way.
I suppose that I could just set it up in init.d to run on boot, but was hoping to not have to deal with another initd process for ease of management...
Thanks for any ideas.
Alan
Nigh 2008-01-11 17:06 -0500, Alan Pinstein pleaded:
I don't know a lot about sockets programming, but I am not sure this makes sense... I don't WANT stunnel to stop listening to those ports; rather it shouldn't ever start. stunnel has a config file, so I'd expect it to only listen to the ports it was told to listen to, which is 4449.
Can you show us the code that is starting Stunnel? Is it running as the apache user? Is it actually being started from apache itself?
If apache (the webserver daemon) is exec'ing Stunnel, it should be closing those sockets. If it's not, you'd still see them as LISTENable. (Now, would stunnel accept on them? I'd think not, because it's bound 4449 and only does listen() on that socket.
But still I think that stunnel is actively listening on these ports. Forked processed just don't inherit sockets from parents AFAIK....
google for 'close on exec'
I suppose that I could just set it up in init.d to run on boot, but was hoping to not have to deal with another initd process for ease of management...
You're better off using init.d, honestly. Else you might get more than one stunnel trying to start up, all that logic to start or not start, etc.
Alan,
On Fri, 11 Jan 2008, Alan Pinstein wrote: [...]
Yes. RHEL5.
The following is an educated guess:
Open connections are open file descriptors, and fork()/exec() do not close open file descriptors. Thus, stunnel is inheriting the open connection. And, since it knows nothing about it, it does not close it or anything like that. So it's not that it activelly listens on it, but only that it does not bother to stop. You might check this theory by trying to connect to the port *after* apache is shut down. If I'm right you should get no answer at all.
I don't know a lot about sockets programming, but I am not sure this makes sense... I don't WANT stunnel to stop listening to those ports; rather it shouldn't ever start. stunnel has a config file, so I'd expect it to only listen to the ports it was told to listen to, which is 4449.
I run lots of child processes from php and none of them end up listening to port 80/443 once the server exits.
Although, now that I think about it, I am not sure I daemonize any processes from a php script...
But still I think that stunnel is actively listening on these ports. Forked processed just don't inherit sockets from parents AFAIK....
Not so.
So, the solution is to have the file descriptors close when exec'ing stunnel. PHP or apache might have some option somewhere to do that (look for "close on exec" or something similarly named), but if not, you might have to write some sort of wrapper to do it. It's a messy thing, because AFAIK there's no clean way to do it short of
for (i = 0; i < [some-hopefuly-large-enough-value]; i++) close(i);
[...]
I've seen this problem discussed in other forums. It recently (re)surfaced in the Exim world. See, for example, the thread which starts at http://lists.exim.org/lurker/message/20080102.003418.fd1f8896.en.html and eventually leads to the rather more informative http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=366124 and http://bugs.php.net/bug.php?id=38915
The consensus seems to be that the problem lies with mod_php or maybe even Apache (though agreement is far from universal)
HTH, Richard
Luis Rodrigo Gallardo Cruz wrote:
for (i = 0; i < [some-hopefuly-large-enough-value]; i++) close(i);
I'd recommend to build (with "gcc -Wall -O2 -s -o closefds closefds.c") the following workaround:
/* closefds.c by Michal Trojnara 2008.01.12 */ /* This code is public domain */
#include <stdio.h> #include <unistd.h>
int main(int argc, char *argv[]) { int i;
for(i=3; i<1023; ++i) close(i); execvp(argv[0], argv+1); perror(argv[0]); return 0; }
Replace "/bin_path/stunnel /conf_path/stunnel.conf" with "/bin_path/closefds /bin_path/stunnel /conf_path/stunnel.conf"
Some reasoning behind the code: 1. stunnel deals fine with fd 0, 1 and 2. 2. It's very unlikely that the calling application will use file descriptors over 1023.
Best regards, Mike