static int xconnect_ftpdata(ftp_host_info_t *server, char *buf) { printf("xconnect_ftpdata++++++++++++++++++++++\n"); char *buf_ptr; unsigned short port_num; /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage] * Server's IP is N1.N2.N3.N4 (we ignore it) * Server's port for data connection is P1*256+P2 */ buf_ptr = strrchr(buf, ')'); if (buf_ptr) *buf_ptr = '\0'; buf_ptr = strrchr(buf, ','); *buf_ptr = '\0'; port_num = xatoul_range(buf_ptr + 1, 0, 255); buf_ptr = strrchr(buf, ','); *buf_ptr = '\0'; port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256; set_nport(server->lsa, htons(port_num)); printf("xconnect_ftpdata============\n"); return xconnect_stream(server->lsa); }
static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa) { char buf[512]; FILE *sfp; char *str; int port; if (!target->user) target->user = xstrdup("anonymous:busybox@"); sfp = open_socket(lsa); if (ftpcmd(NULL, NULL, sfp, buf) != 220) bb_error_msg_and_die("%s", sanitize_string(buf+4)); /* * Splitting username:password pair, * trying to log in */ str = strchr(target->user, ':'); if (str) *str++ = '\0'; switch (ftpcmd("USER ", target->user, sfp, buf)) { case 230: break; case 331: if (ftpcmd("PASS ", str, sfp, buf) == 230) break; /* fall through (failed login) */ default: bb_error_msg_and_die("ftp login: %s", sanitize_string(buf+4)); } ftpcmd("TYPE I", NULL, sfp, buf); /* * Querying file size */ if (ftpcmd("SIZE ", target->path, sfp, buf) == 213) { G.content_len = BB_STRTOOFF(buf+4, NULL, 10); if (G.content_len < 0 || errno) { bb_error_msg_and_die("SIZE value is garbage"); } G.got_clen = 1; } /* * Entering passive mode */ if (ftpcmd("PASV", NULL, sfp, buf) != 227) { pasv_error: bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(buf)); } // Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage] // Server's IP is N1.N2.N3.N4 (we ignore it) // Server's port for data connection is P1*256+P2 str = strrchr(buf, ')'); if (str) str[0] = '\0'; str = strrchr(buf, ','); if (!str) goto pasv_error; port = xatou_range(str+1, 0, 255); *str = '\0'; str = strrchr(buf, ','); if (!str) goto pasv_error; port += xatou_range(str+1, 0, 255) * 256; set_nport(lsa, htons(port)); *dfpp = open_socket(lsa); if (G.beg_range) { sprintf(buf, "REST %"OFF_FMT"u", G.beg_range); if (ftpcmd(buf, NULL, sfp, buf) == 350) G.content_len -= G.beg_range; } if (ftpcmd("RETR ", target->path, sfp, buf) > 150) bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(buf)); return sfp; }
static len_and_sockaddr *str2sockaddr(const char *host, int port, int ai_flags) { int rc; len_and_sockaddr *r = NULL; struct addrinfo *result = NULL; const char *org_host = host; /* only for error msg */ const char *cp; struct addrinfo hint; /* Ugly parsing of host:addr */ if (ENABLE_FEATURE_IPV6 && host[0] == '[') { host++; cp = strchr(host, ']'); if (!cp || cp[1] != ':') { /* Malformed: must have [xx]:nn */ //bb_error_msg_and_die("bad address '%s'", org_host); printf("bad address '%s'", org_host); exit (-1); } //return r; /* return NULL */ } else { cp = strrchr(host, ':'); if (ENABLE_FEATURE_IPV6 && cp && strchr(host, ':') != cp) { /* There is more than one ':' (e.g. "::1") */ cp = NULL; /* it's not a port spec */ } } if (cp) { int sz = cp - host + 1; host = safe_strncpy(alloca(sz), host, sz); if (ENABLE_FEATURE_IPV6 && *cp != ':') cp++; /* skip ']' */ cp++; /* skip ':' */ port = xatou16(cp); } memset(&hint, 0 , sizeof(hint)); #if !ENABLE_FEATURE_IPV6 hint.ai_family = AF_INET; /* do not try to find IPv6 */ #else hint.ai_family = af; #endif /* Needed. Or else we will get each address thrice (or more) for each possible socket type (tcp,udp,raw...): */ hint.ai_socktype = SOCK_STREAM; hint.ai_flags = ai_flags & ~DIE_ON_ERROR; rc = getaddrinfo(host, NULL, &hint, &result); if (rc || !result) { //bb_error_msg("bad address '%s'", org_host); printf("bad address '%s'", org_host); if (ai_flags & DIE_ON_ERROR) exit(-1); goto ret; } r = xmalloc(offsetof(len_and_sockaddr, sa) + result->ai_addrlen); r->len = result->ai_addrlen; memcpy(&r->sa, result->ai_addr, result->ai_addrlen); set_nport(r, htons(port)); ret: freeaddrinfo(result); return r; }
static void send_probe(int seq, int ttl) { int len, res; void *out; /* Payload */ #if ENABLE_TRACEROUTE6 if (dest_lsa->u.sa.sa_family == AF_INET6) { struct outdata6_t *pkt = (struct outdata6_t *) outip; pkt->ident6 = htonl(ident); pkt->seq6 = htonl(seq); /*gettimeofday(&pkt->tv, &tz);*/ } else #endif { outdata->seq = seq; outdata->ttl = ttl; // UNUSED: was storing gettimeofday's result there, but never ever checked it /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ if (option_mask32 & OPT_USE_ICMP) { outicmp->icmp_seq = htons(seq); /* Always calculate checksum for icmp packets */ outicmp->icmp_cksum = 0; outicmp->icmp_cksum = inet_cksum((uint16_t *)outicmp, packlen - (sizeof(*outip) + optlen)); if (outicmp->icmp_cksum == 0) outicmp->icmp_cksum = 0xffff; } } //BUG! verbose is (x & OPT_VERBOSE), not a counter! #if 0 //ENABLE_FEATURE_TRACEROUTE_VERBOSE /* XXX undocumented debugging hack */ if (verbose > 1) { const uint16_t *sp; int nshorts, i; sp = (uint16_t *)outip; nshorts = (unsigned)packlen / sizeof(uint16_t); i = 0; printf("[ %d bytes", packlen); while (--nshorts >= 0) { if ((i++ % 8) == 0) printf("\n\t"); printf(" %04x", ntohs(*sp)); sp++; } if (packlen & 1) { if ((i % 8) == 0) printf("\n\t"); printf(" %02x", *(unsigned char *)sp); } printf("]\n"); } #endif #if ENABLE_TRACEROUTE6 if (dest_lsa->u.sa.sa_family == AF_INET6) { res = setsockopt(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); if (res < 0) bb_perror_msg_and_die("setsockopt UNICAST_HOPS %d", ttl); out = outip; len = packlen; } else #endif { #if defined IP_TTL res = setsockopt(sndsock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); if (res < 0) bb_perror_msg_and_die("setsockopt ttl %d", ttl); #endif out = outicmp; len = packlen - sizeof(*outip); if (!(option_mask32 & OPT_USE_ICMP)) { out = outdata; len -= sizeof(*outudp); set_nport(&dest_lsa->u.sa, htons(port + seq)); } } res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len); if (res != len) bb_info_msg("sent %d octets, ret=%d", len, res); }
int pscan_main(int argc UNUSED_PARAM, char **argv) { const char *opt_max_port = "1024"; /* -P: default max port */ const char *opt_min_port = "1"; /* -p: default min port */ const char *opt_timeout = "5000"; /* -t: default timeout in msec */ /* We estimate rtt and wait rtt*4 before concluding that port is * totally blocked. min rtt of 5 ms may be too low if you are * scanning an Internet host behind saturated/traffic shaped link. * Rule of thumb: with min_rtt of N msec, scanning 1000 ports * will take N seconds at absolute minimum */ const char *opt_min_rtt = "5"; /* -T: default min rtt in msec */ const char *result_str; len_and_sockaddr *lsap; int s; unsigned opt; unsigned port, max_port, nports; unsigned closed_ports = 0; unsigned open_ports = 0; /* all in usec */ unsigned timeout; unsigned min_rtt; unsigned rtt_4; unsigned start, diff; opt_complementary = "=1"; /* exactly one non-option */ opt = getopt32(argv, "cbp:P:t:T:", &opt_min_port, &opt_max_port, &opt_timeout, &opt_min_rtt); argv += optind; max_port = xatou_range(opt_max_port, 1, 65535); port = xatou_range(opt_min_port, 1, max_port); nports = max_port - port + 1; min_rtt = xatou_range(opt_min_rtt, 1, INT_MAX/1000 / 4) * 1000; timeout = xatou_range(opt_timeout, 1, INT_MAX/1000 / 4) * 1000; /* Initial rtt is BIG: */ rtt_4 = timeout; DMSG("min_rtt %u timeout %u", min_rtt, timeout); lsap = xhost2sockaddr(*argv, port); printf("Scanning %s ports %u to %u\n Port\tProto\tState\tService\n", *argv, port, max_port); for (; port <= max_port; port++) { DMSG("rtt %u", rtt_4); /* The SOCK_STREAM socket type is implemented on the TCP/IP protocol. */ set_nport(&lsap->u.sa, htons(port)); s = xsocket(lsap->u.sa.sa_family, SOCK_STREAM, 0); /* We need unblocking socket so we don't need to wait for ETIMEOUT. */ /* Nonblocking connect typically "fails" with errno == EINPROGRESS */ ndelay_on(s); DMSG("connect to port %u", port); result_str = NULL; start = MONOTONIC_US(); if (connect(s, &lsap->u.sa, lsap->len) == 0) { /* Unlikely, for me even localhost fails :) */ DMSG("connect succeeded"); goto open; } /* Check for untypical errors... */ if (errno != EAGAIN && errno != EINPROGRESS && errno != ECONNREFUSED ) { bb_perror_nomsg_and_die(); } diff = 0; while (1) { if (errno == ECONNREFUSED) { if (opt & 1) /* -c: show closed too */ result_str = "closed"; closed_ports++; break; } DERR("port %u errno %d @%u", port, errno, diff); if (diff > rtt_4) { if (opt & 2) /* -b: show blocked too */ result_str = "blocked"; break; } /* Can sleep (much) longer than specified delay. * We check rtt BEFORE we usleep, otherwise * on localhost we'll have no writes done (!) * before we exceed (rather small) rtt */ usleep(rtt_4/8); open: diff = MONOTONIC_US() - start; DMSG("write to port %u @%u", port, diff - start); if (write(s, " ", 1) >= 0) { /* We were able to write to the socket */ open_ports++; result_str = "open"; break; } } DMSG("out of loop @%u", diff); if (result_str) printf("%5u" "\t" "tcp" "\t" "%s" "\t" "%s" "\n", port, result_str, port_name(port)); /* Estimate new rtt - we don't want to wait entire timeout * for each port. *4 allows for rise in net delay. * We increase rtt quickly (rtt_4*4), decrease slowly * (diff is at least rtt_4/8, *4 == rtt_4/2) * because we don't want to accidentally miss ports. */ rtt_4 = diff * 4; if (rtt_4 < min_rtt) rtt_4 = min_rtt; if (rtt_4 > timeout) rtt_4 = timeout; /* Clean up */ close(s); } if (ENABLE_FEATURE_CLEAN_UP) free(lsap); printf("%u closed, %u open, %u timed out (or blocked) ports\n", closed_ports, open_ports, nports - (closed_ports + open_ports)); return EXIT_SUCCESS; }
int ipscan_main(int argc UNUSED_PARAM, char **argv) { len_and_sockaddr *lsap; int sks[max]; int i; unsigned opt; const char *opt_port = "515"; unsigned port; char ips[max][buf_size]; FILE *f; int total = 0; int block_total; struct in_addr inp; int ret = EXIT_SUCCESS; unsigned start; opt = getopt32(argv, "p:", &opt_port); argv += optind; if (*argv == NULL) { f = stdin; } else if ((f = fopen(*argv, "r")) == NULL) { bb_error_msg("Failed to open ip address list file %s.", *argv); return EXIT_FAILURE; } port = xatou_range(opt_port, 1, 65535); do { start = MONOTONIC_US(); for (i = 0; i < max; i ++) { if (fgets(ips[i], buf_size, f) == NULL) { goto test_write; break; } if (!inet_aton(ips[i], &inp)) { bb_error_msg("Invalid IP address %s", ips[i]); ips[i][0] = 0; continue; } lsap = xhost2sockaddr(ips[i], port); set_nport(&lsap->u.sa, htons(port)); sks[i] = xsocket(lsap->u.sa.sa_family, SOCK_STREAM, 0); /* We need unblocking socket so we don't need to wait for ETIMEOUT. */ /* Nonblocking connect typically "fails" with errno == EINPROGRESS */ ndelay_on(sks[i]); if (connect(sks[i], &lsap->u.sa, lsap->len) == 0) { /* Unlikely, for me even localhost fails :) */ bb_info_msg("%s", ips[i]); goto out; break; } } test_write: while (MONOTONIC_US() - start < 1000000) { usleep(10000); } block_total = i; for (i = 0; i < block_total; i++) { if (! ips[i][0]) { continue; } DMSG("checking ip = %s\n", ips[i]); if (write(sks[i], " ", 1) >= 0) { /* We were able to write to the socket */ bb_info_msg("%s", ips[i]); goto out; } close(sks[i]); } total += i; if ( ! (total % max)) { bb_error_msg("scanned %d addresses ...", total); } } while (block_total); ret = EXIT_FAILURE; out: if (ENABLE_FEATURE_CLEAN_UP && lsap) free(lsap); fclose(f); return ret; }
int tcpudpsvd_main(int argc ATTRIBUTE_UNUSED, char **argv) { char *str_C, *str_t; char *user; struct hcc *hccp; const char *instructs; char *msg_per_host = NULL; unsigned len_per_host = len_per_host; /* gcc */ #ifndef SSLSVD struct bb_uidgid_t ugid; #endif bool tcp; uint16_t local_port; char *preset_local_hostname = NULL; char *remote_hostname = remote_hostname; /* for compiler */ char *remote_addr = remote_addr; /* for compiler */ len_and_sockaddr *lsa; len_and_sockaddr local, remote; socklen_t sa_len; int pid; int sock; int conn; unsigned backlog = 20; INIT_G(); tcp = (applet_name[0] == 't'); /* 3+ args, -i at most once, -p implies -h, -v is counter, -b N, -c N */ opt_complementary = "-3:i--i:ph:vv:b+:c+"; #ifdef SSLSVD getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:", &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, &backlog, &str_t, &ssluser, &root, &cert, &key, &verbose ); #else /* "+": stop on first non-option */ getopt32(argv, "+c:C:i:x:u:l:Eb:hpt:v", &cmax, &str_C, &instructs, &instructs, &user, &preset_local_hostname, &backlog, &str_t, &verbose ); #endif if (option_mask32 & OPT_C) { /* -C n[:message] */ max_per_host = bb_strtou(str_C, &str_C, 10); if (str_C[0]) { if (str_C[0] != ':') bb_show_usage(); msg_per_host = str_C + 1; len_per_host = strlen(msg_per_host); } } if (max_per_host > cmax) max_per_host = cmax; if (option_mask32 & OPT_u) { if (!get_uidgid(&ugid, user, 1)) bb_error_msg_and_die("unknown user/group: %s", user); } #ifdef SSLSVD if (option_mask32 & OPT_U) ssluser = optarg; if (option_mask32 & OPT_slash) root = optarg; if (option_mask32 & OPT_Z) cert = optarg; if (option_mask32 & OPT_K) key = optarg; #endif argv += optind; if (!argv[0][0] || LONE_CHAR(argv[0], '0')) argv[0] = (char*)"0.0.0.0"; /* Per-IP flood protection is not thought-out for UDP */ if (!tcp) max_per_host = 0; bb_sanitize_stdio(); /* fd# 0,1,2 must be opened */ #ifdef SSLSVD sslser = user; client = 0; if ((getuid() == 0) && !(option_mask32 & OPT_u)) { xfunc_exitcode = 100; bb_error_msg_and_die("-U ssluser must be set when running as root"); } if (option_mask32 & OPT_u) if (!uidgid_get(&sslugid, ssluser, 1)) { if (errno) { bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser); } bb_error_msg_and_die("unknown user/group '%s'", ssluser); } if (!cert) cert = "./cert.pem"; if (!key) key = cert; if (matrixSslOpen() < 0) fatal("cannot initialize ssl"); if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) { if (client) fatal("cannot read cert, key, or ca file"); fatal("cannot read cert or key file"); } if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0) fatal("cannot create ssl session"); #endif sig_block(SIGCHLD); signal(SIGCHLD, sig_child_handler); bb_signals(BB_FATAL_SIGS, sig_term_handler); signal(SIGPIPE, SIG_IGN); if (max_per_host) ipsvd_perhost_init(cmax); local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0); lsa = xhost2sockaddr(argv[0], local_port); argv += 2; sock = xsocket(lsa->u.sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0); setsockopt_reuseaddr(sock); sa_len = lsa->len; /* I presume sockaddr len stays the same */ xbind(sock, &lsa->u.sa, sa_len); if (tcp) xlisten(sock, backlog); else /* udp: needed for recv_from_to to work: */ socket_want_pktinfo(sock); /* ndelay_off(sock); - it is the default I think? */ #ifndef SSLSVD if (option_mask32 & OPT_u) { /* drop permissions */ xsetgid(ugid.gid); xsetuid(ugid.uid); } #endif if (verbose) { char *addr = xmalloc_sockaddr2dotted(&lsa->u.sa); bb_error_msg("listening on %s, starting", addr); free(addr); #ifndef SSLSVD if (option_mask32 & OPT_u) printf(", uid %u, gid %u", (unsigned)ugid.uid, (unsigned)ugid.gid); #endif } /* Main accept() loop */ again: hccp = NULL; while (cnum >= cmax) wait_for_any_sig(); /* expecting SIGCHLD */ /* Accept a connection to fd #0 */ again1: close(0); again2: sig_unblock(SIGCHLD); local.len = remote.len = sa_len; if (tcp) { conn = accept(sock, &remote.u.sa, &remote.len); } else { /* In case recv_from_to won't be able to recover local addr. * Also sets port - recv_from_to is unable to do it. */ local = *lsa; conn = recv_from_to(sock, NULL, 0, MSG_PEEK, &remote.u.sa, &local.u.sa, sa_len); } sig_block(SIGCHLD); if (conn < 0) { if (errno != EINTR) bb_perror_msg(tcp ? "accept" : "recv"); goto again2; } xmove_fd(tcp ? conn : sock, 0); if (max_per_host) { /* Drop connection immediately if cur_per_host > max_per_host * (minimizing load under SYN flood) */ remote_addr = xmalloc_sockaddr2dotted_noport(&remote.u.sa); cur_per_host = ipsvd_perhost_add(remote_addr, max_per_host, &hccp); if (cur_per_host > max_per_host) { /* ipsvd_perhost_add detected that max is exceeded * (and did not store ip in connection table) */ free(remote_addr); if (msg_per_host) { /* don't block or test for errors */ send(0, msg_per_host, len_per_host, MSG_DONTWAIT); } goto again1; } /* NB: remote_addr is not leaked, it is stored in conn table */ } if (!tcp) { /* Voodoo magic: making udp sockets each receive its own * packets is not trivial, and I still not sure * I do it 100% right. * 1) we have to do it before fork() * 2) order is important - is it right now? */ /* Open new non-connected UDP socket for further clients... */ sock = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0); setsockopt_reuseaddr(sock); /* Make plain write/send work for old socket by supplying default * destination address. This also restricts incoming packets * to ones coming from this remote IP. */ xconnect(0, &remote.u.sa, sa_len); /* hole? at this point we have no wildcard udp socket... * can this cause clients to get "port unreachable" icmp? * Yup, time window is very small, but it exists (is it?) */ /* ..."open new socket", continued */ xbind(sock, &lsa->u.sa, sa_len); socket_want_pktinfo(sock); /* Doesn't work: * we cannot replace fd #0 - we will lose pending packet * which is already buffered for us! And we cannot use fd #1 * instead - it will "intercept" all following packets, but child * does not expect data coming *from fd #1*! */ #if 0 /* Make it so that local addr is fixed to localp->u.sa * and we don't accidentally accept packets to other local IPs. */ /* NB: we possibly bind to the _very_ same_ address & port as the one * already bound in parent! This seems to work in Linux. * (otherwise we can move socket to fd #0 only if bind succeeds) */ close(0); set_nport(localp, htons(local_port)); xmove_fd(xsocket(localp->u.sa.sa_family, SOCK_DGRAM, 0), 0); setsockopt_reuseaddr(0); /* crucial */ xbind(0, &localp->u.sa, localp->len); #endif } pid = vfork(); if (pid == -1) { bb_perror_msg("vfork"); goto again; } if (pid != 0) { /* Parent */ cnum++; if (verbose) connection_status(); if (hccp) hccp->pid = pid; /* clean up changes done by vforked child */ undo_xsetenv(); goto again; } /* Child: prepare env, log, and exec prog */ /* Closing tcp listening socket */ if (tcp) close(sock); { /* vfork alert! every xmalloc in this block should be freed! */ char *local_hostname = local_hostname; /* for compiler */ char *local_addr = NULL; char *free_me0 = NULL; char *free_me1 = NULL; char *free_me2 = NULL; if (verbose || !(option_mask32 & OPT_E)) { if (!max_per_host) /* remote_addr is not yet known */ free_me0 = remote_addr = xmalloc_sockaddr2dotted(&remote.u.sa); if (option_mask32 & OPT_h) { free_me1 = remote_hostname = xmalloc_sockaddr2host_noport(&remote.u.sa); if (!remote_hostname) { bb_error_msg("cannot look up hostname for %s", remote_addr); remote_hostname = remote_addr; } } /* Find out local IP peer connected to. * Errors ignored (I'm not paranoid enough to imagine kernel * which doesn't know local IP). */ if (tcp) getsockname(0, &local.u.sa, &local.len); /* else: for UDP it is done earlier by parent */ local_addr = xmalloc_sockaddr2dotted(&local.u.sa); if (option_mask32 & OPT_h) { local_hostname = preset_local_hostname; if (!local_hostname) { free_me2 = local_hostname = xmalloc_sockaddr2host_noport(&local.u.sa); if (!local_hostname) bb_error_msg_and_die("cannot look up hostname for %s", local_addr); } /* else: local_hostname is not NULL, but is NOT malloced! */ } } if (verbose) { pid = getpid(); if (max_per_host) { bb_error_msg("concurrency %s %u/%u", remote_addr, cur_per_host, max_per_host); } bb_error_msg((option_mask32 & OPT_h) ? "start %u %s-%s (%s-%s)" : "start %u %s-%s", pid, local_addr, remote_addr, local_hostname, remote_hostname); } if (!(option_mask32 & OPT_E)) { /* setup ucspi env */ const char *proto = tcp ? "TCP" : "UDP"; /* Extract "original" destination addr:port * from Linux firewall. Useful when you redirect * an outbond connection to local handler, and it needs * to know where it originally tried to connect */ if (tcp && getsockopt(0, SOL_IP, SO_ORIGINAL_DST, &local.u.sa, &local.len) == 0) { char *addr = xmalloc_sockaddr2dotted(&local.u.sa); xsetenv_plain("TCPORIGDSTADDR", addr); free(addr); } xsetenv_plain("PROTO", proto); xsetenv_proto(proto, "LOCALADDR", local_addr); xsetenv_proto(proto, "REMOTEADDR", remote_addr); if (option_mask32 & OPT_h) { xsetenv_proto(proto, "LOCALHOST", local_hostname); xsetenv_proto(proto, "REMOTEHOST", remote_hostname); } //compat? xsetenv_proto(proto, "REMOTEINFO", ""); /* additional */ if (cur_per_host > 0) /* can not be true for udp */ xsetenv_plain("TCPCONCURRENCY", utoa(cur_per_host)); } free(local_addr); free(free_me0); free(free_me1); free(free_me2); } xdup2(0, 1); signal(SIGTERM, SIG_DFL); signal(SIGPIPE, SIG_DFL); signal(SIGCHLD, SIG_DFL); sig_unblock(SIGCHLD); #ifdef SSLSVD strcpy(id, utoa(pid)); ssl_io(0, argv); #else BB_EXECVP(argv[0], argv); #endif bb_perror_msg_and_die("exec '%s'", argv[0]); }