summaryrefslogtreecommitdiff
path: root/ipsvd
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-04-04 10:16:15 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-04-04 10:16:15 +0000
commit64a15124e71b89dca7b00ba76a2ca821e69b5daa (patch)
treefe1aaf3729d9d7d2f862927fe2009b80d241d730 /ipsvd
parent02fd66885cfab933b8fcd747f680c9c0c7e61ff2 (diff)
downloadbusybox-w32-64a15124e71b89dca7b00ba76a2ca821e69b5daa.tar.gz
busybox-w32-64a15124e71b89dca7b00ba76a2ca821e69b5daa.tar.bz2
busybox-w32-64a15124e71b89dca7b00ba76a2ca821e69b5daa.zip
ipsvd: use IP:PORT syntax for environment vars. Pros:
1. it's saner (matches internal libc sockaddr abstraction). 2. it's smaller. Cons: not compatible with smarden's ipsvd. Fix IPv6 define typos. Stop interpreting options in prog's args. Code size -162 bytes.
Diffstat (limited to 'ipsvd')
-rw-r--r--ipsvd/tcpudp.c120
-rw-r--r--ipsvd/udp_io.c25
2 files changed, 74 insertions, 71 deletions
diff --git a/ipsvd/tcpudp.c b/ipsvd/tcpudp.c
index 6e8ec323c..9f098c32e 100644
--- a/ipsvd/tcpudp.c
+++ b/ipsvd/tcpudp.c
@@ -22,9 +22,9 @@
22 * 22 *
23 * udp server is hacked up by reusing TCP code. It has the following 23 * udp server is hacked up by reusing TCP code. It has the following
24 * limitation inherent in Unix DGRAM sockets implementation: 24 * limitation inherent in Unix DGRAM sockets implementation:
25 * - local IP address is reptrieved (using recvmsg voodoo) but 25 * - local IP address is retrieved (using recvmsg voodoo) but
26 * child's socket is not bound to it (bind cannot be called on 26 * child's socket is not bound to it (bind cannot be called on
27 * already bound socket). Thus you still can get outgoing packets 27 * already bound socket). Thus it still can emit outgoing packets
28 * with wrong sorce IP... 28 * with wrong sorce IP...
29 * - don't know how to retrieve ORIGDST for udp. 29 * - don't know how to retrieve ORIGDST for udp.
30 */ 30 */
@@ -100,7 +100,7 @@ enum {
100 100
101static void connection_status(void) 101static void connection_status(void)
102{ 102{
103 /* UDP and "only 1 client max" TCP don't need this */ 103 /* "only 1 client max" don't need this */
104 if (cmax > 1) 104 if (cmax > 1)
105 printf("%s: info: status %u/%u\n", applet_name, cnum, cmax); 105 printf("%s: info: status %u/%u\n", applet_name, cnum, cmax);
106} 106}
@@ -131,34 +131,35 @@ int tcpudpsvd_main(int argc, char **argv)
131 const char *instructs; 131 const char *instructs;
132 char *msg_per_host = NULL; 132 char *msg_per_host = NULL;
133 unsigned len_per_host = len_per_host; /* gcc */ 133 unsigned len_per_host = len_per_host; /* gcc */
134 int need_hostnames, need_remote_ip; 134#ifndef SSLSVD
135 int tcp; 135 struct bb_uidgid_t ugid;
136#endif
137 bool need_hostnames, need_remote_ip, tcp;
138 uint16_t local_port;
139 char *local_hostname = NULL;
140 char *remote_hostname = (char*)""; /* "" used if no -h */
141 char *local_addr = local_addr; /* gcc */
142 char *remote_addr = remote_addr; /* gcc */
143 char *remote_ip = remote_addr; /* gcc */
144 len_and_sockaddr *lsa;
145 len_and_sockaddr local, remote;
146 socklen_t sa_len;
136 int pid; 147 int pid;
137 int sock; 148 int sock;
138 int conn; 149 int conn;
139 unsigned backlog = 20; 150 unsigned backlog = 20;
140 len_and_sockaddr *lsa; 151
141 len_and_sockaddr local, remote;
142 uint16_t local_port;
143 uint16_t remote_port = remote_port; /* gcc */
144 char *local_hostname = NULL;
145 char *remote_hostname = (char*)""; /* "" used if no -h */
146 char *local_ip = local_ip; /* gcc */
147 char *remote_ip = remote_ip; /* gcc */
148#ifndef SSLSVD
149 struct bb_uidgid_t ugid;
150#endif
151 tcp = (applet_name[0] == 't'); 152 tcp = (applet_name[0] == 't');
152 153
153 /* 3+ args, -i at most once, -p implies -h, -v is counter */ 154 /* 3+ args, -i at most once, -p implies -h, -v is counter */
154 opt_complementary = "-3:?:i--i:ph:vv"; 155 opt_complementary = "-3:?:i--i:ph:vv";
155#ifdef SSLSVD 156#ifdef SSLSVD
156 getopt32(argc, argv, "c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:", 157 getopt32(argc, argv, "+c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:",
157 &str_c, &str_C, &instructs, &instructs, &user, &local_hostname, 158 &str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
158 &str_b, &str_t, &ssluser, &root, &cert, &key, &verbose 159 &str_b, &str_t, &ssluser, &root, &cert, &key, &verbose
159 ); 160 );
160#else 161#else
161 getopt32(argc, argv, "c:C:i:x:u:l:Eb:hpt:v", 162 getopt32(argc, argv, "+c:C:i:x:u:l:Eb:hpt:v",
162 &str_c, &str_C, &instructs, &instructs, &user, &local_hostname, 163 &str_c, &str_C, &instructs, &instructs, &user, &local_hostname,
163 &str_b, &str_t, &verbose 164 &str_b, &str_t, &verbose
164 ); 165 );
@@ -213,10 +214,8 @@ int tcpudpsvd_main(int argc, char **argv)
213 if (option_mask32 & OPT_u) 214 if (option_mask32 & OPT_u)
214 if (!uidgid_get(&sslugid, ssluser, 1)) { 215 if (!uidgid_get(&sslugid, ssluser, 1)) {
215 if (errno) { 216 if (errno) {
216 xfunc_exitcode = 100;
217 bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser); 217 bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser);
218 } 218 }
219 xfunc_exitcode = 111;
220 bb_error_msg_and_die("fatal: unknown user/group '%s'", ssluser); 219 bb_error_msg_and_die("fatal: unknown user/group '%s'", ssluser);
221 } 220 }
222 if (!cert) cert = "./cert.pem"; 221 if (!cert) cert = "./cert.pem";
@@ -244,7 +243,8 @@ int tcpudpsvd_main(int argc, char **argv)
244 lsa = xhost2sockaddr(argv[0], local_port); 243 lsa = xhost2sockaddr(argv[0], local_port);
245 sock = xsocket(lsa->sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0); 244 sock = xsocket(lsa->sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
246 setsockopt_reuseaddr(sock); 245 setsockopt_reuseaddr(sock);
247 xbind(sock, &lsa->sa, lsa->len); 246 sa_len = lsa->len; /* I presume sockaddr len stays the same */
247 xbind(sock, &lsa->sa, sa_len);
248 if (tcp) 248 if (tcp)
249 xlisten(sock, backlog); 249 xlisten(sock, backlog);
250 else /* udp: needed for recv_from_to to work: */ 250 else /* udp: needed for recv_from_to to work: */
@@ -260,9 +260,7 @@ int tcpudpsvd_main(int argc, char **argv)
260#endif 260#endif
261 261
262 if (verbose) { 262 if (verbose) {
263 /* we do it only for ":port" cosmetics... oh well */ 263 char *addr = xmalloc_sockaddr2dotted(&lsa->sa, sa_len);
264 char *addr = xmalloc_sockaddr2dotted(&lsa->sa, lsa->len);
265
266 printf("%s: info: listening on %s", applet_name, addr); 264 printf("%s: info: listening on %s", applet_name, addr);
267 free(addr); 265 free(addr);
268#ifndef SSLSVD 266#ifndef SSLSVD
@@ -287,10 +285,14 @@ int tcpudpsvd_main(int argc, char **argv)
287 again2: 285 again2:
288 sig_unblock(SIGCHLD); 286 sig_unblock(SIGCHLD);
289 if (tcp) { 287 if (tcp) {
290 remote.len = lsa->len; 288 remote.len = sa_len;
291 conn = accept(sock, &remote.sa, &remote.len); 289 conn = accept(sock, &remote.sa, &remote.len);
292 } else 290 } else {
293 conn = recv_from_to(sock, NULL, 0, MSG_PEEK, &remote.sa, &local.sa, lsa->len); 291 /* In case we won't be able to recover local below.
292 * Also sets port - recv_from_to is unable to do it. */
293 local = *lsa;
294 conn = recv_from_to(sock, NULL, 0, MSG_PEEK, &remote.sa, &local.sa, sa_len);
295 }
294 sig_block(SIGCHLD); 296 sig_block(SIGCHLD);
295 if (conn < 0) { 297 if (conn < 0) {
296 if (errno != EINTR) 298 if (errno != EINTR)
@@ -302,7 +304,7 @@ int tcpudpsvd_main(int argc, char **argv)
302 if (max_per_host) { 304 if (max_per_host) {
303 /* Drop connection immediately if cur_per_host > max_per_host 305 /* Drop connection immediately if cur_per_host > max_per_host
304 * (minimizing load under SYN flood) */ 306 * (minimizing load under SYN flood) */
305 remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, lsa->len); 307 remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, sa_len);
306 cur_per_host = ipsvd_perhost_add(remote_ip, max_per_host, &hccp); 308 cur_per_host = ipsvd_perhost_add(remote_ip, max_per_host, &hccp);
307 if (cur_per_host > max_per_host) { 309 if (cur_per_host > max_per_host) {
308 /* ipsvd_perhost_add detected that max is exceeded 310 /* ipsvd_perhost_add detected that max is exceeded
@@ -319,16 +321,21 @@ int tcpudpsvd_main(int argc, char **argv)
319 321
320 if (!tcp) { 322 if (!tcp) {
321 /* Voodoo magic: making udp sockets each receive its own 323 /* Voodoo magic: making udp sockets each receive its own
322 * packets is not trivial */ 324 * packets is not trivial, and I still not sure
325 * I do it 100% right.
326 * 1) we have to do it before fork()
327 * 2) order is important - is it right now? */
323 328
324 /* Make plain write work for this socket by supplying default 329 /* Make plain write/send work for this socket by supplying default
325 * destination address. This also restricts incoming packets 330 * destination address. This also restricts incoming packets
326 * to ones coming from this remote IP. */ 331 * to ones coming from this remote IP. */
327 xconnect(0, &remote.sa, lsa->len); 332 xconnect(0, &remote.sa, sa_len);
333 /* hole? at this point we have no wildcard udp socket...
334 * can this cause clients to get "port unreachable" icmp? */
328 /* Open new non-connected UDP socket for further clients */ 335 /* Open new non-connected UDP socket for further clients */
329 sock = xsocket(lsa->sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0); 336 sock = xsocket(lsa->sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
330 setsockopt_reuseaddr(sock); 337 setsockopt_reuseaddr(sock);
331 xbind(sock, &lsa->sa, lsa->len); 338 xbind(sock, &lsa->sa, sa_len);
332 socket_want_pktinfo(sock); 339 socket_want_pktinfo(sock);
333 } 340 }
334 341
@@ -355,50 +362,44 @@ int tcpudpsvd_main(int argc, char **argv)
355 if (tcp) 362 if (tcp)
356 close(sock); 363 close(sock);
357 364
358 if (need_remote_ip) { 365 if (need_remote_ip)
359 if (!max_per_host) 366 remote_addr = xmalloc_sockaddr2dotted(&remote.sa, sa_len);
360 remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, lsa->len);
361 /* else it is already done */
362 remote_port = get_nport(&remote.sa);
363 remote_port = ntohs(remote_port);
364 }
365 367
366 if (need_hostnames) { 368 if (need_hostnames) {
367 if (option_mask32 & OPT_h) { 369 if (option_mask32 & OPT_h) {
368 remote_hostname = xmalloc_sockaddr2host(&remote.sa, lsa->len); 370 remote_hostname = xmalloc_sockaddr2host_noport(&remote.sa, sa_len);
369 if (!remote_hostname) { 371 if (!remote_hostname) {
370 bb_error_msg("warning: cannot look up hostname for %s", remote_ip); 372 bb_error_msg("warning: cannot look up hostname for %s", remote_addr);
371 remote_hostname = (char*)""; 373 remote_hostname = (char*)"";
372 } 374 }
373 } 375 }
374 /* Find out local IP peer connected to. 376 /* Find out local IP peer connected to.
375 * Errors ignored (I'm not paranoid enough to imagine kernel 377 * Errors ignored (I'm not paranoid enough to imagine kernel
376 * which doesn't know local IP). */ 378 * which doesn't know local IP). */
377 if (tcp) 379 if (tcp) {
380 local.len = sa_len;
378 getsockname(0, &local.sa, &local.len); 381 getsockname(0, &local.sa, &local.len);
379 local_ip = xmalloc_sockaddr2dotted_noport(&local.sa, lsa->len); 382 }
380 local_port = get_nport(&local.sa); 383 local_addr = xmalloc_sockaddr2dotted(&local.sa, sa_len);
381 local_port = ntohs(local_port);
382 if (!local_hostname) { 384 if (!local_hostname) {
383 local_hostname = xmalloc_sockaddr2host_noport(&local.sa, lsa->len); 385 local_hostname = xmalloc_sockaddr2host_noport(&local.sa, sa_len);
384 if (!local_hostname) 386 if (!local_hostname)
385 bb_error_msg_and_die("warning: cannot look up hostname for %s"+9, local_ip); 387 bb_error_msg_and_die("warning: cannot look up hostname for %s"+9, local_addr);
386 } 388 }
387 } 389 }
388 390
389 if (verbose) { 391 if (verbose) {
390 pid = getpid(); 392 pid = getpid();
391 printf("%s: info: pid %u from %s\n", applet_name, pid, remote_ip); 393 printf("%s: info: pid %u from %s\n", applet_name, pid, remote_addr);
392 if (max_per_host) 394 if (max_per_host)
393 printf("%s: info: concurrency %u %s %u/%u\n", 395 printf("%s: info: concurrency %u %s %u/%u\n",
394 applet_name, pid, remote_ip, cur_per_host, max_per_host); 396 applet_name, pid, remote_ip, cur_per_host, max_per_host);
395 printf("%s: info: start %u %s:%s :%s:%s:%u\n", 397 printf("%s: info: start %u %s:%s :%s:%s\n",
396 applet_name, pid, 398 applet_name, pid,
397 local_hostname, local_ip, 399 local_hostname, local_addr,
398 remote_hostname, remote_ip, (unsigned)remote_port); 400 remote_hostname, remote_addr);
399 } 401 }
400 402
401// TODO: stop splitiing port# from IP?
402 if (!(option_mask32 & OPT_E)) { 403 if (!(option_mask32 & OPT_E)) {
403 /* setup ucspi env */ 404 /* setup ucspi env */
404 const char *proto = tcp ? "TCP" : "UDP"; 405 const char *proto = tcp ? "TCP" : "UDP";
@@ -408,19 +409,14 @@ int tcpudpsvd_main(int argc, char **argv)
408 * an outbond connection to local handler, and it needs 409 * an outbond connection to local handler, and it needs
409 * to know where it originally tried to connect */ 410 * to know where it originally tried to connect */
410 if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &lsa->sa, &lsa->len) == 0) { 411 if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &lsa->sa, &lsa->len) == 0) {
411 char *ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len); 412 char *addr = xmalloc_sockaddr2dotted(&lsa->sa, sa_len);
412 unsigned port = get_nport(&lsa->sa); 413 xsetenv("TCPORIGDSTADDR", addr);
413 port = ntohs(port); 414 free(addr);
414 xsetenv("TCPORIGDSTIP", ip);
415 xsetenv("TCPORIGDSTPORT", utoa(port));
416 free(ip);
417 } 415 }
418 xsetenv("PROTO", proto); 416 xsetenv("PROTO", proto);
419 xsetenv_proto(proto, "LOCALIP", local_ip); 417 xsetenv_proto(proto, "LOCALADDR", local_addr);
420 xsetenv_proto(proto, "LOCALPORT", utoa(local_port));
421 xsetenv_proto(proto, "LOCALHOST", local_hostname); 418 xsetenv_proto(proto, "LOCALHOST", local_hostname);
422 xsetenv_proto(proto, "REMOTEIP", remote_ip); 419 xsetenv_proto(proto, "REMOTEADDR", remote_addr);
423 xsetenv_proto(proto, "REMOTEPORT", utoa(remote_port));
424 if (option_mask32 & OPT_h) { 420 if (option_mask32 & OPT_h) {
425 xsetenv_proto(proto, "REMOTEHOST", remote_hostname); 421 xsetenv_proto(proto, "REMOTEHOST", remote_hostname);
426 } 422 }
diff --git a/ipsvd/udp_io.c b/ipsvd/udp_io.c
index 68999d44d..2efc15913 100644
--- a/ipsvd/udp_io.c
+++ b/ipsvd/udp_io.c
@@ -18,12 +18,13 @@ socket_want_pktinfo(int fd)
18#ifdef IP_PKTINFO 18#ifdef IP_PKTINFO
19 setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &const_int_1, sizeof(int)); 19 setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &const_int_1, sizeof(int));
20#endif 20#endif
21#ifdef IPV6_PKTINFO 21#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
22 setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &const_int_1, sizeof(int)); 22 setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &const_int_1, sizeof(int));
23#endif 23#endif
24} 24}
25 25
26 26
27#ifdef UNUSED
27ssize_t 28ssize_t
28send_to_from(int fd, void *buf, size_t len, int flags, 29send_to_from(int fd, void *buf, size_t len, int flags,
29 const struct sockaddr *from, const struct sockaddr *to, 30 const struct sockaddr *from, const struct sockaddr *to,
@@ -34,8 +35,11 @@ send_to_from(int fd, void *buf, size_t len, int flags,
34#else 35#else
35 struct iovec iov[1]; 36 struct iovec iov[1];
36 struct msghdr msg; 37 struct msghdr msg;
37 char cbuf[LSA_SIZEOF_SA]; 38 char cbuf[sizeof(struct in_pktinfo)
38 /* actually, max(sizeof(in_pktinfo),sizeof(in6_pktinfo)) */ 39#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
40 | sizeof(struct in6_pktinfo) /* (a|b) is poor man's max(a,b) */
41#endif
42 ];
39 struct cmsghdr* cmsgptr; 43 struct cmsghdr* cmsgptr;
40 44
41 if (from->sa_family != AF_INET 45 if (from->sa_family != AF_INET
@@ -73,11 +77,11 @@ send_to_from(int fd, void *buf, size_t len, int flags,
73 /* pktptr->ipi_ifindex = 0; -- already done by memset(cbuf...) */ 77 /* pktptr->ipi_ifindex = 0; -- already done by memset(cbuf...) */
74 pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr; 78 pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr;
75 } 79 }
76#if ENABLE_FEATURE_IPV6 && defined(IP6_PKTINFO) 80#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
77 else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) { 81 else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) {
78 struct in6_pktinfo *pktptr; 82 struct in6_pktinfo *pktptr;
79 cmsgptr->cmsg_level = IPPROTO_IPV6; 83 cmsgptr->cmsg_level = IPPROTO_IPV6;
80 cmsgptr->cmsg_type = IP6_PKTINFO; 84 cmsgptr->cmsg_type = IPV6_PKTINFO;
81 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 85 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
82 pktptr = (struct in6_pktinfo *)(CMSG_DATA(cmsgptr)); 86 pktptr = (struct in6_pktinfo *)(CMSG_DATA(cmsgptr));
83 /* pktptr->ipi6_ifindex = 0; -- already done by memset(cbuf...) */ 87 /* pktptr->ipi6_ifindex = 0; -- already done by memset(cbuf...) */
@@ -87,8 +91,12 @@ send_to_from(int fd, void *buf, size_t len, int flags,
87 return sendmsg(fd, &msg, flags); 91 return sendmsg(fd, &msg, flags);
88#endif 92#endif
89} 93}
94#endif /* UNUSED */
90 95
91/* NB: this will never set port# in *to! */ 96/* NB: this will never set port# in 'to'!
97 * _Only_ IP/IPv6 address part of 'to' is _maybe_ modified.
98 * Typical usage is to preinit it with "default" value
99 * before calling recv_from_to(). */
92ssize_t 100ssize_t
93recv_from_to(int fd, void *buf, size_t len, int flags, 101recv_from_to(int fd, void *buf, size_t len, int flags,
94 struct sockaddr *from, struct sockaddr *to, 102 struct sockaddr *from, struct sockaddr *to,
@@ -123,7 +131,6 @@ recv_from_to(int fd, void *buf, size_t len, int flags,
123 return recv_length; 131 return recv_length;
124 132
125 /* Here we try to retrieve destination IP and memorize it */ 133 /* Here we try to retrieve destination IP and memorize it */
126 memset(to, 0, sa_size);
127 for (cmsgptr = CMSG_FIRSTHDR(&msg); 134 for (cmsgptr = CMSG_FIRSTHDR(&msg);
128 cmsgptr != NULL; 135 cmsgptr != NULL;
129 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr) 136 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)
@@ -138,9 +145,9 @@ recv_from_to(int fd, void *buf, size_t len, int flags,
138#undef pktinfo 145#undef pktinfo
139 break; 146 break;
140 } 147 }
141#if ENABLE_FEATURE_IPV6 && defined(IP6_PKTINFO) 148#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
142 if (cmsgptr->cmsg_level == IPPROTO_IPV6 149 if (cmsgptr->cmsg_level == IPPROTO_IPV6
143 && cmsgptr->cmsg_type == IP6_PKTINFO 150 && cmsgptr->cmsg_type == IPV6_PKTINFO
144 ) { 151 ) {
145#define pktinfo(cmsgptr) ( (struct in6_pktinfo*)(CMSG_DATA(cmsgptr)) ) 152#define pktinfo(cmsgptr) ( (struct in6_pktinfo*)(CMSG_DATA(cmsgptr)) )
146 to->sa_family = AF_INET6; 153 to->sa_family = AF_INET6;