/* alter the global _res nameserver structure to use an explicit dns server instead of what is in /etc/resolv.conf */ static void set_default_dns(const char *server) { len_and_sockaddr *lsa; if (!server) return; /* NB: this works even with, say, "[::1]:5353"! :) */ lsa = xhost2sockaddr(server, 53); if (lsa->u.sa.sa_family == AF_INET) { _res.nscount = 1; /* struct copy */ _res.nsaddr_list[0] = lsa->u.sin; } #if ENABLE_FEATURE_IPV6 /* Hoped libc can cope with IPv4 address there too. * No such luck, glibc 2.4 segfaults even with IPv6, * maybe I misunderstand how to make glibc use IPv6 addr? * (uclibc 0.9.31+ should work) */ if (lsa->u.sa.sa_family == AF_INET6) { // glibc neither SEGVs nor sends any dgrams with this // (strace shows no socket ops): //_res.nscount = 0; _res._u._ext.nscount = 1; /* store a pointer to part of malloc'ed lsa */ _res._u._ext.nsaddrs[0] = &lsa->u.sin6; /* must not free(lsa)! */ } #endif }
static void add_peers(char *s) { peer_t *p; p = xzalloc(sizeof(*p)); p->p_lsa = xhost2sockaddr(s, 123); p->p_dotted = xmalloc_sockaddr2dotted_noport(&p->p_lsa->u.sa); p->p_fd = -1; p->p_xmt_msg.m_status = MODE_CLIENT | (NTP_VERSION << 3); p->p_trustlevel = TRUSTLEVEL_PATHETIC; p->next_action_time = time(NULL); /* = set_next(p, 0); */ llist_add_to(&G.ntp_peers, p); G.peer_cnt++; }
int wget_main(int argc UNUSED_PARAM, char **argv) { char buf[512]; struct host_info server, target; len_and_sockaddr *lsa; unsigned opt; int redir_limit; char *proxy = NULL; char *dir_prefix = NULL; #if ENABLE_FEATURE_WGET_LONG_OPTIONS char *post_data; char *extra_headers = NULL; llist_t *headers_llist = NULL; #endif FILE *sfp; /* socket to web/ftp server */ FILE *dfp; /* socket to ftp server (data) */ char *fname_out; /* where to direct output (-O) */ int output_fd = -1; bool use_proxy; /* Use proxies if env vars are set */ const char *proxy_flag = "on"; /* Use proxies if env vars are set */ const char *user_agent = "Wget";/* "User-Agent" header field */ static const char keywords[] ALIGN1 = "content-length\0""transfer-encoding\0""chunked\0""location\0"; enum { KEY_content_length = 1, KEY_transfer_encoding, KEY_chunked, KEY_location }; #if ENABLE_FEATURE_WGET_LONG_OPTIONS static const char wget_longopts[] ALIGN1 = /* name, has_arg, val */ "continue\0" No_argument "c" "spider\0" No_argument "s" "quiet\0" No_argument "q" "output-document\0" Required_argument "O" "directory-prefix\0" Required_argument "P" "proxy\0" Required_argument "Y" "user-agent\0" Required_argument "U" /* Ignored: */ // "tries\0" Required_argument "t" // "timeout\0" Required_argument "T" /* Ignored (we always use PASV): */ "passive-ftp\0" No_argument "\xff" "header\0" Required_argument "\xfe" "post-data\0" Required_argument "\xfd" /* Ignored (we don't do ssl) */ "no-check-certificate\0" No_argument "\xfc" ; #endif INIT_G(); #if ENABLE_FEATURE_WGET_LONG_OPTIONS applet_long_options = wget_longopts; #endif /* server.allocated = target.allocated = NULL; */ opt_complementary = "-1" IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::"); opt = getopt32(argv, "csqO:P:Y:U:" /*ignored:*/ "t:T:", &fname_out, &dir_prefix, &proxy_flag, &user_agent, NULL, /* -t RETRIES */ NULL /* -T NETWORK_READ_TIMEOUT */ IF_FEATURE_WGET_LONG_OPTIONS(, &headers_llist) IF_FEATURE_WGET_LONG_OPTIONS(, &post_data) ); #if ENABLE_FEATURE_WGET_LONG_OPTIONS if (headers_llist) { int size = 1; char *cp; llist_t *ll = headers_llist; while (ll) { size += strlen(ll->data) + 2; ll = ll->link; } extra_headers = cp = xmalloc(size); while (headers_llist) { cp += sprintf(cp, "%s\r\n", (char*)llist_pop(&headers_llist)); } } #endif /* TODO: compat issue: should handle "wget URL1 URL2..." */ target.user = NULL; parse_url(argv[optind], &target); /* Use the proxy if necessary */ use_proxy = (strcmp(proxy_flag, "off") != 0); if (use_proxy) { proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy"); if (proxy && proxy[0]) { server.user = NULL; parse_url(proxy, &server); } else { use_proxy = 0; } } if (!use_proxy) { server.port = target.port; if (ENABLE_FEATURE_IPV6) { server.host = xstrdup(target.host); } else { server.host = target.host; } } if (ENABLE_FEATURE_IPV6) strip_ipv6_scope_id(target.host); /* Guess an output filename, if there was no -O FILE */ if (!(opt & WGET_OPT_OUTNAME)) { fname_out = bb_get_last_path_component_nostrip(target.path); /* handle "wget http://kernel.org//" */ if (fname_out[0] == '/' || !fname_out[0]) fname_out = (char*)"index.html"; /* -P DIR is considered only if there was no -O FILE */ if (dir_prefix) fname_out = concat_path_file(dir_prefix, fname_out); } else { if (LONE_DASH(fname_out)) { /* -O - */ output_fd = 1; opt &= ~WGET_OPT_CONTINUE; } } #if ENABLE_FEATURE_WGET_STATUSBAR G.curfile = bb_get_last_path_component_nostrip(fname_out); #endif /* Impossible? if ((opt & WGET_OPT_CONTINUE) && !fname_out) bb_error_msg_and_die("can't specify continue (-c) without a filename (-O)"); */ /* Determine where to start transfer */ if (opt & WGET_OPT_CONTINUE) { output_fd = open(fname_out, O_WRONLY); if (output_fd >= 0) { G.beg_range = xlseek(output_fd, 0, SEEK_END); } /* File doesn't exist. We do not create file here yet. * We are not sure it exists on remove side */ } redir_limit = 5; resolve_lsa: lsa = xhost2sockaddr(server.host, server.port); if (!(opt & WGET_OPT_QUIET)) { char *s = xmalloc_sockaddr2dotted(&lsa->u.sa); fprintf(stderr, "Connecting to %s (%s)\n", server.host, s); free(s); } establish_session: if (use_proxy || !target.is_ftp) { /* * HTTP session */ char *str; int status; /* Open socket to http server */ sfp = open_socket(lsa); /* Send HTTP request */ if (use_proxy) { fprintf(sfp, "GET %stp://%s/%s HTTP/1.1\r\n", target.is_ftp ? "f" : "ht", target.host, target.path); } else { if (opt & WGET_OPT_POST_DATA) fprintf(sfp, "POST /%s HTTP/1.1\r\n", target.path); else fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); } fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", target.host, user_agent); #if ENABLE_FEATURE_WGET_AUTHENTICATION if (target.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, base64enc_512(buf, target.user)); } if (use_proxy && server.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n", base64enc_512(buf, server.user)); } #endif if (G.beg_range) fprintf(sfp, "Range: bytes=%"OFF_FMT"u-\r\n", G.beg_range); #if ENABLE_FEATURE_WGET_LONG_OPTIONS if (extra_headers) fputs(extra_headers, sfp); if (opt & WGET_OPT_POST_DATA) { char *estr = URL_escape(post_data); fprintf(sfp, "Content-Type: application/x-www-form-urlencoded\r\n"); fprintf(sfp, "Content-Length: %u\r\n" "\r\n" "%s", (int) strlen(estr), estr); /*fprintf(sfp, "Connection: Keep-Alive\r\n\r\n");*/ /*fprintf(sfp, "%s\r\n", estr);*/ free(estr); } else #endif { /* If "Connection:" is needed, document why */ fprintf(sfp, /* "Connection: close\r\n" */ "\r\n"); } /* * Retrieve HTTP response line and check for "200" status code. */ read_response: if (fgets(buf, sizeof(buf), sfp) == NULL) bb_error_msg_and_die("no response from server"); str = buf; str = skip_non_whitespace(str); str = skip_whitespace(str); // FIXME: no error check // xatou wouldn't work: "200 OK" status = atoi(str); switch (status) { case 0: case 100: while (gethdr(buf, sizeof(buf), sfp /*, &n*/) != NULL) /* eat all remaining headers */; goto read_response; case 200: /* Response 204 doesn't say "null file", it says "metadata has changed but data didn't": "10.2.5 204 No Content The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation. The response MAY include new or updated metainformation in the form of entity-headers, which if present SHOULD be associated with the requested variant. If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent's active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent's active view. The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields." However, in real world it was observed that some web servers (e.g. Boa/0.94.14rc21) simply use code 204 when file size is zero. */ case 204: break; case 300: /* redirection */ case 301: case 302: case 303: break; case 206: if (G.beg_range) break; /* fall through */ default: bb_error_msg_and_die("server returned error: %s", sanitize_string(buf)); } /* * Retrieve HTTP headers. */ while ((str = gethdr(buf, sizeof(buf), sfp /*, &n*/)) != NULL) { /* gethdr converted "FOO:" string to lowercase */ smalluint key; /* strip trailing whitespace */ char *s = strchrnul(str, '\0') - 1; while (s >= str && (*s == ' ' || *s == '\t')) { *s = '\0'; s--; } key = index_in_strings(keywords, buf) + 1; if (key == KEY_content_length) { G.content_len = BB_STRTOOFF(str, NULL, 10); if (G.content_len < 0 || errno) { bb_error_msg_and_die("content-length %s is garbage", sanitize_string(str)); } G.got_clen = 1; continue; } if (key == KEY_transfer_encoding) { if (index_in_strings(keywords, str_tolower(str)) + 1 != KEY_chunked) bb_error_msg_and_die("transfer encoding '%s' is not supported", sanitize_string(str)); G.chunked = G.got_clen = 1; } if (key == KEY_location && status >= 300) { if (--redir_limit == 0) bb_error_msg_and_die("too many redirections"); fclose(sfp); G.got_clen = 0; G.chunked = 0; if (str[0] == '/') /* free(target.allocated); */ target.path = /* target.allocated = */ xstrdup(str+1); /* lsa stays the same: it's on the same server */ else { parse_url(str, &target); if (!use_proxy) { server.host = target.host; /* strip_ipv6_scope_id(target.host); - no! */ /* we assume remote never gives us IPv6 addr with scope id */ server.port = target.port; free(lsa); goto resolve_lsa; } /* else: lsa stays the same: we use proxy */ } goto establish_session; } } // if (status >= 300) // bb_error_msg_and_die("bad redirection (no Location: header from server)"); /* For HTTP, data is pumped over the same connection */ dfp = sfp; } else { /* * FTP session */ sfp = prepare_ftp_session(&dfp, &target, lsa); } if (opt & WGET_OPT_SPIDER) { if (ENABLE_FEATURE_CLEAN_UP) fclose(sfp); return EXIT_SUCCESS; } if (output_fd < 0) { int o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL; /* compat with wget: -O FILE can overwrite */ if (opt & WGET_OPT_OUTNAME) o_flags = O_WRONLY | O_CREAT | O_TRUNC; output_fd = xopen(fname_out, o_flags); } retrieve_file_data(dfp, output_fd); xclose(output_fd); if (dfp != sfp) { /* It's ftp. Close it properly */ fclose(dfp); if (ftpcmd(NULL, NULL, sfp, buf) != 226) bb_error_msg_and_die("ftp error: %s", sanitize_string(buf+4)); /* ftpcmd("QUIT", NULL, sfp, buf); - why bother? */ } return EXIT_SUCCESS; }
static void download_one_url(const char *url) { bool use_proxy; /* Use proxies if env vars are set */ int redir_limit; len_and_sockaddr *lsa; FILE *sfp; /* socket to web/ftp server */ FILE *dfp; /* socket to ftp server (data) */ char *proxy = NULL; char *fname_out_alloc; char *redirected_path = NULL; struct host_info server; struct host_info target; server.allocated = NULL; target.allocated = NULL; server.user = NULL; target.user = NULL; parse_url(url, &target); /* Use the proxy if necessary */ use_proxy = (strcmp(G.proxy_flag, "off") != 0); if (use_proxy) { proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy"); use_proxy = (proxy && proxy[0]); if (use_proxy) parse_url(proxy, &server); } if (!use_proxy) { server.port = target.port; if (ENABLE_FEATURE_IPV6) { //free(server.allocated); - can't be non-NULL server.host = server.allocated = xstrdup(target.host); } else { server.host = target.host; } } if (ENABLE_FEATURE_IPV6) strip_ipv6_scope_id(target.host); /* If there was no -O FILE, guess output filename */ fname_out_alloc = NULL; if (!(option_mask32 & WGET_OPT_OUTNAME)) { G.fname_out = bb_get_last_path_component_nostrip(target.path); /* handle "wget http://kernel.org//" */ if (G.fname_out[0] == '/' || !G.fname_out[0]) G.fname_out = (char*)"index.html"; /* -P DIR is considered only if there was no -O FILE */ if (G.dir_prefix) G.fname_out = fname_out_alloc = concat_path_file(G.dir_prefix, G.fname_out); else { /* redirects may free target.path later, need to make a copy */ G.fname_out = fname_out_alloc = xstrdup(G.fname_out); } } #if ENABLE_FEATURE_WGET_STATUSBAR G.curfile = bb_get_last_path_component_nostrip(G.fname_out); #endif /* Determine where to start transfer */ G.beg_range = 0; if (option_mask32 & WGET_OPT_CONTINUE) { G.output_fd = open(G.fname_out, O_WRONLY); if (G.output_fd >= 0) { G.beg_range = xlseek(G.output_fd, 0, SEEK_END); } /* File doesn't exist. We do not create file here yet. * We are not sure it exists on remote side */ } redir_limit = 5; resolve_lsa: lsa = xhost2sockaddr(server.host, server.port); if (!(option_mask32 & WGET_OPT_QUIET)) { char *s = xmalloc_sockaddr2dotted(&lsa->u.sa); fprintf(stderr, "Connecting to %s (%s)\n", server.host, s); free(s); } establish_session: /*G.content_len = 0; - redundant, got_clen = 0 is enough */ G.got_clen = 0; G.chunked = 0; if (use_proxy || !target.is_ftp) { /* * HTTP session */ char *str; int status; /* Open socket to http server */ sfp = open_socket(lsa); /* Send HTTP request */ if (use_proxy) { fprintf(sfp, "GET %stp://%s/%s HTTP/1.1\r\n", target.is_ftp ? "f" : "ht", target.host, target.path); } else { if (option_mask32 & WGET_OPT_POST_DATA) fprintf(sfp, "POST /%s HTTP/1.1\r\n", target.path); else fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); } fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", target.host, G.user_agent); /* Ask server to close the connection as soon as we are done * (IOW: we do not intend to send more requests) */ fprintf(sfp, "Connection: close\r\n"); #if ENABLE_FEATURE_WGET_AUTHENTICATION if (target.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, base64enc(target.user)); } if (use_proxy && server.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n", base64enc(server.user)); } #endif if (G.beg_range != 0) fprintf(sfp, "Range: bytes=%"OFF_FMT"u-\r\n", G.beg_range); #if ENABLE_FEATURE_WGET_LONG_OPTIONS if (G.extra_headers) fputs(G.extra_headers, sfp); if (option_mask32 & WGET_OPT_POST_DATA) { fprintf(sfp, "Content-Type: application/x-www-form-urlencoded\r\n" "Content-Length: %u\r\n" "\r\n" "%s", (int) strlen(G.post_data), G.post_data ); } else #endif { fprintf(sfp, "\r\n"); } fflush(sfp); /* * Retrieve HTTP response line and check for "200" status code. */ read_response: fgets_and_trim(sfp); str = G.wget_buf; str = skip_non_whitespace(str); str = skip_whitespace(str); // FIXME: no error check // xatou wouldn't work: "200 OK" status = atoi(str); switch (status) { case 0: case 100: while (gethdr(sfp) != NULL) /* eat all remaining headers */; goto read_response; case 200: /* Response 204 doesn't say "null file", it says "metadata has changed but data didn't": "10.2.5 204 No Content The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation. The response MAY include new or updated metainformation in the form of entity-headers, which if present SHOULD be associated with the requested variant. If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent's active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent's active view. The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields." However, in real world it was observed that some web servers (e.g. Boa/0.94.14rc21) simply use code 204 when file size is zero. */ case 204: if (G.beg_range != 0) { /* "Range:..." was not honored by the server. * Restart download from the beginning. */ reset_beg_range_to_zero(); } break; case 300: /* redirection */ case 301: case 302: case 303: break; case 206: /* Partial Content */ if (G.beg_range != 0) /* "Range:..." worked. Good. */ break; /* Partial Content even though we did not ask for it??? */ /* fall through */ default: bb_error_msg_and_die("server returned error: %s", sanitize_string(G.wget_buf)); } /* * Retrieve HTTP headers. */ while ((str = gethdr(sfp)) != NULL) { static const char keywords[] ALIGN1 = "content-length\0""transfer-encoding\0""location\0"; enum { KEY_content_length = 1, KEY_transfer_encoding, KEY_location }; smalluint key; /* gethdr converted "FOO:" string to lowercase */ /* strip trailing whitespace */ char *s = strchrnul(str, '\0') - 1; while (s >= str && (*s == ' ' || *s == '\t')) { *s = '\0'; s--; } key = index_in_strings(keywords, G.wget_buf) + 1; if (key == KEY_content_length) { G.content_len = BB_STRTOOFF(str, NULL, 10); if (G.content_len < 0 || errno) { bb_error_msg_and_die("content-length %s is garbage", sanitize_string(str)); } G.got_clen = 1; continue; } if (key == KEY_transfer_encoding) { if (strcmp(str_tolower(str), "chunked") != 0) bb_error_msg_and_die("transfer encoding '%s' is not supported", sanitize_string(str)); G.chunked = 1; } if (key == KEY_location && status >= 300) { if (--redir_limit == 0) bb_error_msg_and_die("too many redirections"); fclose(sfp); if (str[0] == '/') { free(redirected_path); target.path = redirected_path = xstrdup(str+1); /* lsa stays the same: it's on the same server */ } else { parse_url(str, &target); if (!use_proxy) { free(server.allocated); server.allocated = NULL; server.host = target.host; /* strip_ipv6_scope_id(target.host); - no! */ /* we assume remote never gives us IPv6 addr with scope id */ server.port = target.port; free(lsa); goto resolve_lsa; } /* else: lsa stays the same: we use proxy */ } goto establish_session; } } // if (status >= 300) // bb_error_msg_and_die("bad redirection (no Location: header from server)"); /* For HTTP, data is pumped over the same connection */ dfp = sfp; } else {
int ifconfig_main(int argc, char **argv) { struct ifreq ifr; struct sockaddr_in sai; #if ENABLE_FEATURE_IFCONFIG_HW struct sockaddr sa; #endif const struct arg1opt *a1op; const struct options *op; int sockfd; /* socket fd we use to manipulate stuff with */ int selector; #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS unsigned int mask; unsigned int did_flags; unsigned int sai_hostname, sai_netmask; #else unsigned char mask; unsigned char did_flags; #endif char *p; /*char host[128];*/ const char *host = NULL; /* make gcc happy */ did_flags = 0; #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS sai_hostname = 0; sai_netmask = 0; #endif /* skip argv[0] */ ++argv; --argc; #if ENABLE_FEATURE_IFCONFIG_STATUS if (argc > 0 && (argv[0][0] == '-' && argv[0][1] == 'a' && !argv[0][2])) { interface_opt_a = 1; --argc; ++argv; } #endif if (argc <= 1) { #if ENABLE_FEATURE_IFCONFIG_STATUS return display_interfaces(argc ? *argv : NULL); #else bb_error_msg_and_die("no support for status display"); #endif } /* Create a channel to the NET kernel. */ sockfd = xsocket(AF_INET, SOCK_DGRAM, 0); /* get interface name */ safe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ); /* Process the remaining arguments. */ while (*++argv != (char *) NULL) { p = *argv; mask = N_MASK; if (*p == '-') { /* If the arg starts with '-'... */ ++p; /* advance past it and */ mask = M_MASK; /* set the appropriate mask. */ } for (op = OptArray; op->name; op++) { /* Find table entry. */ if (strcmp(p, op->name) == 0) { /* If name matches... */ mask &= op->flags; if (mask) /* set the mask and go. */ goto FOUND_ARG; /* If we get here, there was a valid arg with an */ /* invalid '-' prefix. */ bb_error_msg_and_die("bad: '%s'", p-1); } } /* We fell through, so treat as possible hostname. */ a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1; mask = op->arg_flags; goto HOSTNAME; FOUND_ARG: if (mask & ARG_MASK) { mask = op->arg_flags; a1op = Arg1Opt + (op - OptArray); if (mask & A_NETMASK & did_flags) bb_show_usage(); if (*++argv == NULL) { if (mask & A_ARG_REQ) bb_show_usage(); --argv; mask &= A_SET_AFTER; /* just for broadcast */ } else { /* got an arg so process it */ HOSTNAME: did_flags |= (mask & (A_NETMASK|A_HOSTNAME)); if (mask & A_CAST_HOST_COPY) { #if ENABLE_FEATURE_IFCONFIG_HW if (mask & A_CAST_RESOLVE) { #endif #if ENABLE_FEATURE_IPV6 char *prefix; int prefix_len = 0; #endif /*safe_strncpy(host, *argv, (sizeof host));*/ host = *argv; #if ENABLE_FEATURE_IPV6 prefix = strchr(host, '/'); if (prefix) { prefix_len = xatou_range(prefix + 1, 0, 128); *prefix = '\0'; } #endif sai.sin_family = AF_INET; sai.sin_port = 0; if (!strcmp(host, bb_str_default)) { /* Default is special, meaning 0.0.0.0. */ sai.sin_addr.s_addr = INADDR_ANY; } #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS else if ((host[0] == '+' && !host[1]) && (mask & A_BROADCAST) && (did_flags & (A_NETMASK|A_HOSTNAME)) == (A_NETMASK|A_HOSTNAME) ) { /* + is special, meaning broadcast is derived. */ sai.sin_addr.s_addr = (~sai_netmask) | (sai_hostname & sai_netmask); } #endif else { len_and_sockaddr *lsa; if (strcmp(host, "inet") == 0) continue; /* compat stuff */ lsa = xhost2sockaddr(host, 0); #if ENABLE_FEATURE_IPV6 if (lsa->sa.sa_family == AF_INET6) { int sockfd6; struct in6_ifreq ifr6; memcpy((char *) &ifr6.ifr6_addr, (char *) &(lsa->sin6.sin6_addr), sizeof(struct in6_addr)); /* Create a channel to the NET kernel. */ sockfd6 = xsocket(AF_INET6, SOCK_DGRAM, 0); if (ioctl(sockfd6, SIOGIFINDEX, &ifr) < 0) bb_perror_msg_and_die("SIOGIFINDEX"); ifr6.ifr6_ifindex = ifr.ifr_ifindex; ifr6.ifr6_prefixlen = prefix_len; if (ioctl(sockfd6, a1op->selector, &ifr6) < 0) bb_perror_msg_and_die(a1op->name); if (ENABLE_FEATURE_CLEAN_UP) free(lsa); continue; } #endif sai.sin_addr = lsa->sin.sin_addr; if (ENABLE_FEATURE_CLEAN_UP) free(lsa); } #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS if (mask & A_HOSTNAME) sai_hostname = sai.sin_addr.s_addr; if (mask & A_NETMASK) sai_netmask = sai.sin_addr.s_addr; #endif p = (char *) &sai; #if ENABLE_FEATURE_IFCONFIG_HW } else { /* A_CAST_HOST_COPY_IN_ETHER */ /* This is the "hw" arg case. */ if (strcmp("ether", *argv) || !*++argv) bb_show_usage(); /*safe_strncpy(host, *argv, sizeof(host));*/ host = *argv; if (in_ether(host, &sa)) bb_error_msg_and_die("invalid hw-addr %s", host); p = (char *) &sa; } #endif memcpy( (((char *)&ifr) + a1op->ifr_offset), p, sizeof(struct sockaddr)); } else { /* FIXME: error check?? */ unsigned long i = strtoul(*argv, NULL, 0); p = ((char *)&ifr) + a1op->ifr_offset; #if ENABLE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ if (mask & A_MAP_TYPE) { if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) bb_perror_msg_and_die("SIOCGIFMAP"); if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) *((unsigned char *) p) = i; else if (mask & A_MAP_USHORT) *((unsigned short *) p) = i; else *((unsigned long *) p) = i; } else #endif if (mask & A_CAST_CHAR_PTR) *((caddr_t *) p) = (caddr_t) i; else /* A_CAST_INT */ *((int *) p) = i; } if (ioctl(sockfd, a1op->selector, &ifr) < 0) bb_perror_msg_and_die(a1op->name); #ifdef QUESTIONABLE_ALIAS_CASE if (mask & A_COLON_CHK) { /* * Don't do the set_flag() if the address is an alias with * a '-' at the end, since it's deleted already! - Roman * * Should really use regex.h here, not sure though how well * it'll go with the cross-platform support etc. */ char *ptr; short int found_colon = 0; for (ptr = ifr.ifr_name; *ptr; ptr++) if (*ptr == ':') found_colon++; if (found_colon && ptr[-1] == '-') continue; } #endif } if (!(mask & A_SET_AFTER)) continue; mask = N_SET; } if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) bb_perror_msg_and_die("SIOCGIFFLAGS"); selector = op->selector; if (mask & SET_MASK) ifr.ifr_flags |= selector; else ifr.ifr_flags &= ~selector; if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) bb_perror_msg_and_die("SIOCSIFFLAGS"); } /* while () */ if (ENABLE_FEATURE_CLEAN_UP) close(sockfd); return 0; }
FILE *start_wget(char *url, int *total) { char buf[512]; struct host_info server, target; len_and_sockaddr *lsa; int redir_limit; #if ENABLE_FEATURE_WGET_LONG_OPTIONS char *post_data; char *extra_headers = NULL; llist_t *headers_llist = NULL; #endif FILE *sfp; /* socket to web/ftp server */ int use_proxy = 0; /* Use proxies if env vars are set */ const char *user_agent = "Wget";/* "User-Agent" header field */ struct globals state; char *str; int status; bzero(&state, sizeof(state)); static const char keywords[] = "content-length\0""transfer-encoding\0""chunked\0""location\0"; enum { KEY_content_length = 1, KEY_transfer_encoding, KEY_chunked, KEY_location }; target.user = NULL; parse_url(url, &target); state.timeout_seconds = 900; server.port = target.port; server.host = target.host; #if 0 if (opt & WGET_OPT_CONTINUE) { output_fd = open(fname_out, O_WRONLY); if (output_fd >= 0) { state.beg_range = xlseek(output_fd, 0, SEEK_END); } /* File doesn't exist. We do not create file here yet. * We are not sure it exists on remove side */ } #endif redir_limit = 5; resolve_lsa: lsa = xhost2sockaddr(server.host, server.port); establish_session: /* * HTTP session */ /* Open socket to http server */ sfp = open_socket(lsa); if (!sfp) { ERROR("Couldn't connect to %s:%d", server.host, server.port); return NULL; } /* Send HTTP request */ fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", target.host, user_agent); /* Ask server to close the connection as soon as we are done * (IOW: we do not intend to send more requests) */ fprintf(sfp, "Connection: close\r\n"); if (state.beg_range) fprintf(sfp, "Range: bytes=%lu-\r\n", state.beg_range); fprintf(sfp, "\r\n"); fflush(sfp); /* * Retrieve HTTP response line and check for "200" status code. */ read_response: if (fgets(buf, sizeof(buf), sfp) == NULL) ERROR("no response from server"); str = buf; str = skip_non_whitespace(str); str = skip_whitespace(str); // FIXME: no error check // xatou wouldn't work: "200 OK" status = atoi(str); switch (status) { case 0: case 100: while (gethdr(buf, sizeof(buf), sfp /*, &n*/) != NULL) /* eat all remaining headers */; goto read_response; case 200: /* Response 204 doesn't say "null file", it says "metadata has changed but data didn't": "10.2.5 204 No Content The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation. The response MAY include new or updated metainformation in the form of entity-headers, which if present SHOULD be associated with the requested variant. If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent's active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent's active view. The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields." However, in real world it was observed that some web servers (e.g. Boa/0.94.14rc21) simply use code 204 when file size is zero. */ case 204: break; case 300: /* redirection */ case 301: case 302: case 303: break; case 206: if (state.beg_range) break; /* fall through */ default: ERROR("server returned error: %s", sanitize_string(buf)); } /* * Retrieve HTTP headers. */ while ((str = gethdr(buf, sizeof(buf), sfp /*, &n*/)) != NULL) { /* gethdr converted "FOO:" string to lowercase */ smalluint key; /* strip trailing whitespace */ char *s = strchrnul(str, '\0') - 1; while (s >= str && (*s == ' ' || *s == '\t')) { *s = '\0'; s--; } key = index_in_strings(keywords, buf) + 1; if (key == KEY_content_length) { state.content_len = strtoul(str, NULL, 10); state.total_len = strtoul(str, NULL, 10); if (state.content_len < 0 || errno) { ERROR("content-length %s is garbage", sanitize_string(str)); } state.got_clen = 1; continue; } if (key == KEY_transfer_encoding) { if (index_in_strings(keywords, str_tolower(str)) + 1 != KEY_chunked) ERROR("transfer encoding '%s' is not supported", sanitize_string(str)); state.chunked = state.got_clen = 1; } if (key == KEY_location && status >= 300) { if (--redir_limit == 0) ERROR("too many redirections"); fclose(sfp); state.got_clen = 0; state.chunked = 0; if (str[0] == '/') /* free(target.allocated); */ target.path = /* target.allocated = */ strdup(str+1); /* lsa stays the same: it's on the same server */ else { parse_url(str, &target); if (!use_proxy) { server.host = target.host; server.port = target.port; free(lsa); goto resolve_lsa; } /* else: lsa stays the same: we use proxy */ } goto establish_session; } } // if (status >= 300) // ERROR("bad redirection (no Location: header from server)"); if (total) *total = state.content_len; ndelay_off(fileno(sfp)); clearerr(sfp); return sfp; #if 0 if (retrieve_file_data(&state, sfp, progress, handle, data)) return -1; handle(data, NULL, 0); return EXIT_SUCCESS; #endif }
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]); }