dnscrypto-proxy: Support files updated.
[tomato.git] / release / src / router / vsftpd / standalone.c
blob9de4c1cfb55332af8f43ee267fbcc80fdce13b8b
1 /*
2 * Part of Very Secure FTPd
3 * Licence: GPL v2
4 * Author: Chris Evans
5 * standalone.c
7 * Code to listen on the network and launch children servants.
8 */
10 #include "standalone.h"
12 #include "parseconf.h"
13 #include "tunables.h"
14 #include "sysutil.h"
15 #include "sysdeputil.h"
16 #include "utility.h"
17 #include "defs.h"
18 #include "hash.h"
19 #include "str.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;
40 int listen_sock = -1;
41 int retval;
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();
50 if (forkret > 0)
52 /* Parent, just exit */
53 vsf_sysutil_exit(0);
55 /* Son, close standard FDs to avoid SSH hang-on-exit */
56 vsf_sysutil_reopen_standard_fds();
57 vsf_sysutil_make_session_leader();
59 if (tunable_listen)
61 listen_sock = vsf_sysutil_get_ipv4_sock();
63 else
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);
79 if (tunable_listen)
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);
88 else
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");
102 else
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);
111 else
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);
117 str_free(&addr_str);
118 if (!p_raw_addr)
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);
137 while (1)
139 struct vsf_client_launch child_info;
140 void* p_raw_addr;
141 int new_child;
142 int new_client_sock;
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))
147 continue;
149 ++s_children;
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);
154 if (tunable_isolate)
156 if (tunable_http_enable && tunable_isolate_network)
158 new_child = vsf_sysutil_fork_isolate_all_failok();
160 else
162 new_child = vsf_sysutil_fork_isolate_failok();
165 else
167 new_child = vsf_sysutil_fork_failok();
169 if (new_child != 0)
171 /* Parent context */
172 vsf_sysutil_close(new_client_sock);
173 if (new_child > 0)
175 hash_add_entry(s_p_pid_ip_hash, (void*)&new_child, p_raw_addr);
177 else
179 /* fork() failed, clear up! */
180 --s_children;
181 drop_ip_count(p_raw_addr);
183 /* Fall through to while() loop and accept() again */
185 else
187 /* Child context */
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.
194 return child_info;
199 static void
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);
212 static void
213 drop_ip_count(void* p_raw_addr)
215 unsigned int count;
216 unsigned int* p_count =
217 (unsigned int*)hash_lookup_entry(s_p_ip_count_hash, p_raw_addr);
218 if (!p_count)
220 bug("IP address missing from hash");
222 count = *p_count;
223 if (!count)
225 bug("zero count for IP address");
227 count--;
228 *p_count = count;
229 if (!count)
231 hash_free_entry(s_p_ip_count_hash, p_raw_addr);
235 static void
236 handle_sigchld(void* duff)
238 unsigned int reap_one = 1;
239 (void) duff;
240 while (reap_one)
242 reap_one = (unsigned int)vsf_sysutil_wait_reap_one();
243 if (reap_one)
245 struct vsf_sysutil_ipaddr* p_ip;
246 /* Account total number of instances */
247 --s_children;
248 /* Account per-IP limit */
249 p_ip = (struct vsf_sysutil_ipaddr*)
250 hash_lookup_entry(s_p_pid_ip_hash, (void*)&reap_one);
251 drop_ip_count(p_ip);
252 hash_free_entry(s_p_pid_ip_hash, (void*)&reap_one);
257 static void
258 handle_sighup(void* duff)
260 (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);
266 static unsigned int
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;
271 int shift = 24;
272 unsigned int i;
273 for (i = 0; i < s_ipaddr_size; ++i)
275 val ^= p_raw_ip[i] << shift;
276 shift -= 8;
277 if (shift < 0)
279 shift = 24;
282 return val % buckets;
285 static unsigned int
286 hash_pid(unsigned int buckets, void* p_key)
288 unsigned int* p_pid = (unsigned int*)p_key;
289 return (*p_pid) % buckets;
292 static unsigned int
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);
297 unsigned int count;
298 if (!p_count)
300 count = 1;
301 hash_add_entry(s_p_ip_count_hash, p_ipaddr, (void*)&count);
303 else
305 count = *p_count;
306 count++;
307 *p_count = count;
309 return count;