2 * Part of Very Secure FTPd
7 * Code to listen on the network and launch children servants.
10 #include "standalone.h"
12 #include "parseconf.h"
15 #include "sysdeputil.h"
20 #include "ipaddrparse.h"
22 static unsigned int s_children
;
23 static struct hash
* s_p_ip_count_hash
;
24 static struct hash
* s_p_pid_ip_hash
;
25 static unsigned int s_ipaddr_size
;
27 static void handle_sigchld(void* duff
);
28 static void handle_sighup(void* duff
);
29 static void prepare_child(int sockfd
);
30 static unsigned int handle_ip_count(void* p_raw_addr
);
31 static void drop_ip_count(void* p_raw_addr
);
33 static unsigned int hash_ip(unsigned int buckets
, void* p_key
);
34 static unsigned int hash_pid(unsigned int buckets
, void* p_key
);
36 struct vsf_client_launch
37 vsf_standalone_main(void)
39 struct vsf_sysutil_sockaddr
* p_accept_addr
= 0;
42 s_ipaddr_size
= vsf_sysutil_get_ipaddr_size();
43 if (tunable_listen
&& tunable_listen_ipv6
)
45 die("run two copies of vsftpd for IPv4 and IPv6");
47 if (tunable_background
)
49 int forkret
= vsf_sysutil_fork();
52 /* Parent, just exit */
55 /* Son, close standard FDs to avoid SSH hang-on-exit */
56 vsf_sysutil_reopen_standard_fds();
57 vsf_sysutil_make_session_leader();
61 listen_sock
= vsf_sysutil_get_ipv4_sock();
65 listen_sock
= vsf_sysutil_get_ipv6_sock();
67 vsf_sysutil_activate_reuseaddr(listen_sock
);
69 s_p_ip_count_hash
= hash_alloc(256, s_ipaddr_size
,
70 sizeof(unsigned int), hash_ip
);
71 s_p_pid_ip_hash
= hash_alloc(256, sizeof(int),
72 s_ipaddr_size
, hash_pid
);
73 if (tunable_setproctitle_enable
)
75 vsf_sysutil_setproctitle("LISTENER");
77 vsf_sysutil_install_sighandler(kVSFSysUtilSigCHLD
, handle_sigchld
, 0, 1);
78 vsf_sysutil_install_sighandler(kVSFSysUtilSigHUP
, handle_sighup
, 0, 1);
81 struct vsf_sysutil_sockaddr
* p_sockaddr
= 0;
82 vsf_sysutil_sockaddr_alloc_ipv4(&p_sockaddr
);
83 vsf_sysutil_sockaddr_set_port(p_sockaddr
, tunable_listen_port
);
84 if (!tunable_listen_address
)
86 vsf_sysutil_sockaddr_set_any(p_sockaddr
);
90 if (!vsf_sysutil_inet_aton(tunable_listen_address
, p_sockaddr
))
92 die2("bad listen_address: ", tunable_listen_address
);
95 retval
= vsf_sysutil_bind(listen_sock
, p_sockaddr
);
96 vsf_sysutil_free(p_sockaddr
);
97 if (vsf_sysutil_retval_is_error(retval
))
99 die("could not bind listening IPv4 socket");
104 struct vsf_sysutil_sockaddr
* p_sockaddr
= 0;
105 vsf_sysutil_sockaddr_alloc_ipv6(&p_sockaddr
);
106 vsf_sysutil_sockaddr_set_port(p_sockaddr
, tunable_listen_port
);
107 if (!tunable_listen_address6
)
109 vsf_sysutil_sockaddr_set_any(p_sockaddr
);
113 struct mystr addr_str
= INIT_MYSTR
;
114 const unsigned char* p_raw_addr
;
115 str_alloc_text(&addr_str
, tunable_listen_address6
);
116 p_raw_addr
= vsf_sysutil_parse_ipv6(&addr_str
);
120 die2("bad listen_address6: ", tunable_listen_address6
);
122 vsf_sysutil_sockaddr_set_ipv6addr(p_sockaddr
, p_raw_addr
);
124 retval
= vsf_sysutil_bind(listen_sock
, p_sockaddr
);
125 vsf_sysutil_free(p_sockaddr
);
126 if (vsf_sysutil_retval_is_error(retval
))
128 die("could not bind listening IPv6 socket");
131 retval
= vsf_sysutil_listen(listen_sock
, VSFTP_LISTEN_BACKLOG
);
132 if (vsf_sysutil_retval_is_error(retval
))
134 die("could not listen");
136 vsf_sysutil_sockaddr_alloc(&p_accept_addr
);
139 struct vsf_client_launch child_info
;
143 new_client_sock
= vsf_sysutil_accept_timeout(
144 listen_sock
, p_accept_addr
, 0);
145 if (vsf_sysutil_retval_is_error(new_client_sock
))
150 child_info
.num_children
= s_children
;
151 child_info
.num_this_ip
= 0;
152 p_raw_addr
= vsf_sysutil_sockaddr_get_raw_addr(p_accept_addr
);
153 child_info
.num_this_ip
= handle_ip_count(p_raw_addr
);
156 if (tunable_http_enable
&& tunable_isolate_network
)
158 new_child
= vsf_sysutil_fork_isolate_all_failok();
162 new_child
= vsf_sysutil_fork_isolate_failok();
167 new_child
= vsf_sysutil_fork_failok();
172 vsf_sysutil_close(new_client_sock
);
175 hash_add_entry(s_p_pid_ip_hash
, (void*)&new_child
, p_raw_addr
);
179 /* fork() failed, clear up! */
181 drop_ip_count(p_raw_addr
);
183 /* Fall through to while() loop and accept() again */
188 vsf_set_die_if_parent_dies();
189 vsf_sysutil_close(listen_sock
);
190 prepare_child(new_client_sock
);
191 /* By returning here we "launch" the child process with the same
192 * contract as xinetd would provide.
200 prepare_child(int new_client_sock
)
202 /* We must satisfy the contract: command socket on fd 0, 1, 2 */
203 vsf_sysutil_dupfd2(new_client_sock
, 0);
204 vsf_sysutil_dupfd2(new_client_sock
, 1);
205 vsf_sysutil_dupfd2(new_client_sock
, 2);
206 if (new_client_sock
> 2)
208 vsf_sysutil_close(new_client_sock
);
213 drop_ip_count(void* p_raw_addr
)
216 unsigned int* p_count
=
217 (unsigned int*)hash_lookup_entry(s_p_ip_count_hash
, p_raw_addr
);
220 bug("IP address missing from hash");
225 bug("zero count for IP address");
231 hash_free_entry(s_p_ip_count_hash
, p_raw_addr
);
236 handle_sigchld(void* duff
)
238 unsigned int reap_one
= 1;
242 reap_one
= (unsigned int)vsf_sysutil_wait_reap_one();
245 struct vsf_sysutil_ipaddr
* p_ip
;
246 /* Account total number of instances */
248 /* Account per-IP limit */
249 p_ip
= (struct vsf_sysutil_ipaddr
*)
250 hash_lookup_entry(s_p_pid_ip_hash
, (void*)&reap_one
);
252 hash_free_entry(s_p_pid_ip_hash
, (void*)&reap_one
);
258 handle_sighup(void* duff
)
261 /* We don't crash the out the listener if an invalid config was added */
262 tunables_load_defaults();
263 vsf_parseconf_load_file(0, 0);
267 hash_ip(unsigned int buckets
, void* p_key
)
269 const unsigned char* p_raw_ip
= (const unsigned char*)p_key
;
270 unsigned int val
= 0;
273 for (i
= 0; i
< s_ipaddr_size
; ++i
)
275 val
^= p_raw_ip
[i
] << shift
;
282 return val
% buckets
;
286 hash_pid(unsigned int buckets
, void* p_key
)
288 unsigned int* p_pid
= (unsigned int*)p_key
;
289 return (*p_pid
) % buckets
;
293 handle_ip_count(void* p_ipaddr
)
295 unsigned int* p_count
=
296 (unsigned int*)hash_lookup_entry(s_p_ip_count_hash
, p_ipaddr
);
301 hash_add_entry(s_p_ip_count_hash
, p_ipaddr
, (void*)&count
);