static time_t askremotedate(const char *host) { unsigned long int nett, localt; const char *port="37"; int fd; if (getservbyname("time", "tcp") != NULL) port="time"; fd = xconnect(host, port); if (read(fd, (void *)&nett, 4) != 4) /* read time from server */ error_msg_and_die("%s did not send the complete time", host); close(fd); /* convert from network byte order to local byte order. * RFC 868 time is the number of seconds * since 00:00 (midnight) 1 January 1900 GMT * the RFC 868 time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT * Subtract the RFC 868 time to get Linux epoch */ localt= ntohl(nett) - RFC_868_BIAS; return(localt); }
static FILE *ftp_login(ftp_host_info_t *server) { FILE *control_stream; char buf[512]; /* Connect to the command socket */ control_stream = fdopen(xconnect(server->s_in), "r+"); if (control_stream == NULL) { bb_perror_msg_and_die("Couldnt open control stream"); } if (ftpcmd(NULL, NULL, control_stream, buf) != 220) { bb_error_msg_and_die("%s", buf + 4); } /* Login to the server */ switch (ftpcmd("USER ", server->user, control_stream, buf)) { case 230: break; case 331: if (ftpcmd("PASS ", server->password, control_stream, buf) != 230) { bb_error_msg_and_die("PASS error: %s", buf + 4); } break; default: bb_error_msg_and_die("USER error: %s", buf + 4); } ftpcmd("TYPE I", NULL, control_stream, buf); return(control_stream); }
static time_t askremotedate(const char *host) { unsigned long int nett, localt; struct sockaddr_in s_in; int fd; bb_lookup_host(&s_in, host); s_in.sin_port = bb_lookup_port("time", "tcp", 37); /* Add a timeout for dead or non accessable servers */ alarm(10); signal(SIGALRM, socket_timeout); fd = xconnect(&s_in); if (safe_read(fd, (void *)&nett, 4) != 4) /* read time from server */ bb_error_msg_and_die("%s did not send the complete time", host); close(fd); /* convert from network byte order to local byte order. * RFC 868 time is the number of seconds * since 00:00 (midnight) 1 January 1900 GMT * the RFC 868 time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT * Subtract the RFC 868 time to get Linux epoch */ localt= ntohl(nett) - RFC_868_BIAS; return(localt); }
static void proceed_request_stack(int srv) { struct parse_state srv_state = { .state = ST_CMD, .p_idx = 0 }; struct request *r; int i=0; for(r = req_stack ; r != NULL ; r = r->next) { proceed_request(srv, r); while(parse(srv, &srv_state, proceed_response)); } } static void client() { int sd; struct request quit = { .command = CMD_QUIT }; struct sockaddr_un s_addr = { .sun_family = AF_UNIX }; struct sigaction act = { .sa_handler = srv_timeout, .sa_flags = 0 }; /* ensure this lient won't live more than REQUEST_TIMEOUT seconds */ sigfillset(&act.sa_mask); sigaction(SIGALRM, &act, NULL); alarm(REQUEST_TIMEOUT); /* socket creation */ sd = xsocket(AF_UNIX, SOCK_STREAM, 0); /* bind socket to the specified sock_path */ strncpy(s_addr.sun_path, sock_path, UNIX_PATH_MAX); /* connect to the server */ xconnect(sd, (struct sockaddr *)&s_addr, SUN_LEN(&s_addr)); proceed_request_stack(sd); /* quit only after the request has been proceeded */ proceed_request(sd, &quit); } int main(int argc, char * const argv[]) { /* get program name */ prog_name = (const char *)strrchr(argv[0], '/'); prog_name = prog_name ? (prog_name + 1) : argv[0]; /* parse command line and build the request stack */ cmdline(argc, argv); /* start client */ client(); return EXIT_SUCCESS; }
int connect_to_server(int protonum, char *ip, int port) { struct sockaddr_in *srv_addr; int sockfd; sockfd = xsocket(AF_INET, SOCK_STREAM, protonum); srv_addr = xmalloc_and_set(NULL, sizeof(*srv_addr)); srv_addr->sin_family = AF_INET; srv_addr->sin_addr.s_addr = inet_addr(ip); srv_addr->sin_port = htons(port); xconnect(sockfd, (struct sockaddr *)srv_addr, sizeof(*srv_addr)); free(srv_addr); return (sockfd); }
static int xconnect_ftpdata(ftp_host_info_t *server, const char *buf) { char *buf_ptr; unsigned short port_num; buf_ptr = strrchr(buf, ','); *buf_ptr = '\0'; port_num = atoi(buf_ptr + 1); buf_ptr = strrchr(buf, ','); *buf_ptr = '\0'; port_num += atoi(buf_ptr + 1) * 256; server->s_in->sin_port=htons(port_num); return(xconnect(server->s_in)); }
static int xconnect_ftpdata(const char *target_host, const char *buf) { char *buf_ptr; char data_port[6]; unsigned short port_num; buf_ptr = strrchr(buf, ','); *buf_ptr = '\0'; port_num = atoi(buf_ptr + 1); buf_ptr = strrchr(buf, ','); *buf_ptr = '\0'; port_num += atoi(buf_ptr + 1) * 256; sprintf(data_port, "%d", port_num); return(xconnect(target_host, data_port)); }
static void xclient (const char *pf) { int sfd, i; int64_t nbytes; char buf[1024] = {}; char *ubuf; char host[1024] = {}; sprintf (host, "%s%s", pf, "://127.0.0.1:18897"); randstr (buf, 1024); BUG_ON ( (sfd = xconnect (host) ) < 0); for (i = 0; i < cnt; i++) { nbytes = rand() % 1024; ubuf = ubuf_alloc (nbytes); memcpy (ubuf, buf, nbytes); BUG_ON (0 != xsend (sfd, ubuf) ); BUG_ON (0 != xrecv (sfd, &ubuf) ); DEBUG_OFF ("%d recv response", sfd); assert (memcmp (ubuf, buf, nbytes) == 0); ubuf_free (ubuf); } xclose (sfd); }
int xbind_connect(const len_and_sockaddr *lsa, const char *ip) { int fd; /*Start of MNT 2008-10-13 14:40 for 传输超时检测 by z65940*/ g_TimeoutCnt = ATP_CONNECT_TIMEOUT_D; // 每个命令的超时检测 /*End of MNT 2008-10-13 14:40 for by z65940*/ #if 0 /*Added by yehuisheng00183935@20110806 修改IPv6链路地址访问问题--使用链路地址时,必须指定参数"sin6_scope_id"*/ if ( AF_INET6 == lsa->u.sa.sa_family ) { if (IN6_IS_ADDR_LINKLOCAL(&(((struct sockaddr_in6 *)(&(lsa->u.sa)))->sin6_addr))) { ((struct sockaddr_in6 *)(&(lsa->u.sa)))->sin6_scope_id = if_nametoindex("br0"); } } /*Added by yehuisheng00183935@20110806 修改IPv6链路地址访问问题--使用链路地址时,必须指定参数"sin6_scope_id"*/ #endif if (NULL == ip) { // No bind, the same as xconnect_stream fd = xconnect_stream(lsa); /*Start of MNT 2008-10-13 14:40 for 传输超时检测 by z65940*/ g_TimeoutCnt = -1; /*End of MNT 2008-10-13 14:40 for by z65940*/ return fd; } // Bind to specified local interface //fd = create_and_bind_stream_or_die(ip, get_nport(&(lsa->u.sa))); fd = create_and_bind_stream_or_die(ip, 0); xconnect(fd, &(lsa->u.sa), lsa->len); /*Start of MNT 2008-10-13 14:40 for 传输超时检测 by z65940*/ g_TimeoutCnt = -1; /*End of MNT 2008-10-13 14:40 for by z65940*/ return fd; }
int xconnect_tcp_v4(struct sockaddr_in *s_addr) { int s = xsocket(AF_INET, SOCK_STREAM, 0); xconnect(s, (struct sockaddr*) s_addr, sizeof(*s_addr)); return s; }
int arping_main(int argc UNUSED_PARAM, char **argv) { const char *device = "eth0"; char *source = NULL; char *target; unsigned char *packet; char *err_str; INIT_G(); sock_fd = xsocket(AF_PACKET, SOCK_DGRAM, 0); // Drop suid root privileges // Need to remove SUID_NEVER from applets.h for this to work //xsetuid(getuid()); err_str = xasprintf("interface %s %%s", device); { unsigned opt; char *str_timeout; /* Dad also sets quit_on_reply. * Advert also sets unsolicited. */ opt_complementary = "=1:Df:AU:c+"; opt = getopt32(argv, "DUAqfbc:w:I:s:", &count, &str_timeout, &device, &source); if (opt & 0x80) /* -w: timeout */ timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000; //if (opt & 0x200) /* -s: source */ option_mask32 &= 0x3f; /* set respective flags */ } target = argv[optind]; xfunc_error_retval = 2; { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy_IFNAMSIZ(ifr.ifr_name, device); /* We use ifr.ifr_name in error msg so that problem * with truncated name will be visible */ ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &ifr, err_str, "not found"); me.sll_ifindex = ifr.ifr_ifindex; xioctl(sock_fd, SIOCGIFFLAGS, (char *) &ifr); if (!(ifr.ifr_flags & IFF_UP)) { bb_error_msg_and_die(err_str, "is down"); } if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) { bb_error_msg(err_str, "is not ARPable"); return (option_mask32 & DAD ? 0 : 2); } } /* if (!inet_aton(target, &dst)) - not needed */ { len_and_sockaddr *lsa; lsa = xhost_and_af2sockaddr(target, 0, AF_INET); dst = lsa->u.sin.sin_addr; if (ENABLE_FEATURE_CLEAN_UP) free(lsa); } if (source && !inet_aton(source, &src)) { bb_error_msg_and_die("invalid source address %s", source); } if ((option_mask32 & (DAD|UNSOLICITED)) == UNSOLICITED && src.s_addr == 0) src = dst; if (!(option_mask32 & DAD) || src.s_addr) { struct sockaddr_in saddr; int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); setsockopt_bindtodevice(probe_fd, device); memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; if (src.s_addr) { /* Check that this is indeed our IP */ saddr.sin_addr = src; xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); } else { /* !(option_mask32 & DAD) case */ /* Find IP address on this iface */ socklen_t alen = sizeof(saddr); saddr.sin_port = htons(1025); saddr.sin_addr = dst; if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, &const_int_1, sizeof(const_int_1)) == -1) bb_perror_msg("setsockopt(SO_DONTROUTE)"); xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1) { bb_perror_msg_and_die("getsockname"); } if (saddr.sin_family != AF_INET) bb_error_msg_and_die("no IP address configured"); src = saddr.sin_addr; } close(probe_fd); } me.sll_family = AF_PACKET; //me.sll_ifindex = ifindex; - done before me.sll_protocol = htons(ETH_P_ARP); xbind(sock_fd, (struct sockaddr *) &me, sizeof(me)); { socklen_t alen = sizeof(me); if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1) { bb_perror_msg_and_die("getsockname"); } } if (me.sll_halen == 0) { bb_error_msg(err_str, "is not ARPable (no ll address)"); return (option_mask32 & DAD ? 0 : 2); } he = me; memset(he.sll_addr, -1, he.sll_halen); if (!(option_mask32 & QUIET)) { /* inet_ntoa uses static storage, can't use in same printf */ printf("ARPING to %s", inet_ntoa(dst)); printf(" from %s via %s\n", inet_ntoa(src), device); } signal_SA_RESTART_empty_mask(SIGINT, (void (*)(int))finish); signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher); catcher(); packet = xmalloc(4096); while (1) { sigset_t sset, osset; struct sockaddr_ll from; socklen_t alen = sizeof(from); int cc; cc = recvfrom(sock_fd, packet, 4096, 0, (struct sockaddr *) &from, &alen); if (cc < 0) { bb_perror_msg("recvfrom"); continue; } sigemptyset(&sset); sigaddset(&sset, SIGALRM); sigaddset(&sset, SIGINT); sigprocmask(SIG_BLOCK, &sset, &osset); recv_pack(packet, cc, &from); sigprocmask(SIG_SETMASK, &osset, NULL); } }
int arping_main(int argc, char **argv) { const char *device = "eth0"; int ifindex; char *source = NULL; char *target; s = xsocket(PF_PACKET, SOCK_DGRAM, 0); // Drop suid root privileges xsetuid(getuid()); { unsigned opt; char *_count, *_timeout; /* Dad also sets quit_on_reply. * Advert also sets unsolicited. */ opt_complementary = "Df:AU"; opt = getopt32(argc, argv, "DUAqfbc:w:i:s:", &_count, &_timeout, &device, &source); cfg |= opt & 0x3f; /* set respective flags */ if (opt & 0x40) /* -c: count */ count = xatou(_count); if (opt & 0x80) /* -w: timeout */ timeout = xatoul_range(_timeout, 0, INT_MAX/2000); //if (opt & 0x100) /* -i: interface */ if (strlen(device) > IF_NAMESIZE) { bb_error_msg_and_die("interface name '%s' is too long", device); } //if (opt & 0x200) /* -s: source */ } argc -= optind; argv += optind; if (argc != 1) bb_show_usage(); target = *argv; xfunc_error_retval = 2; { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, device, IFNAMSIZ - 1); if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { bb_error_msg_and_die("interface %s not found", device); } ifindex = ifr.ifr_ifindex; if (ioctl(s, SIOCGIFFLAGS, (char *) &ifr)) { bb_error_msg_and_die("SIOCGIFFLAGS"); } if (!(ifr.ifr_flags & IFF_UP)) { bb_error_msg_and_die("interface %s is down", device); } if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) { bb_error_msg("interface %s is not ARPable", device); return (cfg & dad ? 0 : 2); } } if (!inet_aton(target, &dst)) { len_and_sockaddr *lsa; lsa = xhost_and_af2sockaddr(target, 0, AF_INET); memcpy(&dst, &lsa->sin.sin_addr.s_addr, 4); if (ENABLE_FEATURE_CLEAN_UP) free(lsa); } if (source && !inet_aton(source, &src)) { bb_error_msg_and_die("invalid source address %s", source); } if (!(cfg & dad) && (cfg & unsolicited) && src.s_addr == 0) src = dst; if (!(cfg & dad) || src.s_addr) { struct sockaddr_in saddr; int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); if (device) { if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1) == -1) bb_error_msg("warning: interface %s is ignored", device); } memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; if (src.s_addr) { saddr.sin_addr = src; xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); } else if (!(cfg & dad)) { socklen_t alen = sizeof(saddr); saddr.sin_port = htons(1025); saddr.sin_addr = dst; if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, &const_int_1, sizeof(const_int_1)) == -1) bb_perror_msg("warning: setsockopt(SO_DONTROUTE)"); xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1) { bb_error_msg_and_die("getsockname"); } src = saddr.sin_addr; } close(probe_fd); } me.sll_family = AF_PACKET; me.sll_ifindex = ifindex; me.sll_protocol = htons(ETH_P_ARP); xbind(s, (struct sockaddr *) &me, sizeof(me)); { socklen_t alen = sizeof(me); if (getsockname(s, (struct sockaddr *) &me, &alen) == -1) { bb_error_msg_and_die("getsockname"); } } if (me.sll_halen == 0) { bb_error_msg("interface \"%s\" is not ARPable (no ll address)", device); return (cfg & dad ? 0 : 2); } he = me; memset(he.sll_addr, -1, he.sll_halen); if (!(cfg & quiet)) { printf("ARPING to %s from %s via %s\n", inet_ntoa(dst), inet_ntoa(src), device ? device : "unknown"); } if (!src.s_addr && !(cfg & dad)) { bb_error_msg_and_die("no src address in the non-DAD mode"); } { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_RESTART; sa.sa_handler = (void (*)(int)) finish; sigaction(SIGINT, &sa, NULL); sa.sa_handler = (void (*)(int)) catcher; sigaction(SIGALRM, &sa, NULL); } catcher(); while (1) { sigset_t sset, osset; RESERVE_CONFIG_UBUFFER(packet, 4096); struct sockaddr_ll from; socklen_t alen = sizeof(from); int cc; cc = recvfrom(s, packet, 4096, 0, (struct sockaddr *) &from, &alen); if (cc < 0) { bb_perror_msg("recvfrom"); continue; } sigemptyset(&sset); sigaddset(&sset, SIGALRM); sigaddset(&sset, SIGINT); sigprocmask(SIG_BLOCK, &sset, &osset); recv_pack(packet, cc, &from); sigprocmask(SIG_SETMASK, &osset, NULL); RELEASE_CONFIG_BUFFER(packet); } }
extern int telnet_main(int argc, char** argv) { int len; struct sockaddr_in s_in; #ifdef USE_POLL struct pollfd ufds[2]; #else fd_set readfds; int maxfd; #endif #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN int opt; #endif #ifdef CONFIG_FEATURE_AUTOWIDTH get_terminal_width_height(0, &win_width, &win_height); #endif #ifdef CONFIG_FEATURE_TELNET_TTYPE ttype = getenv("TERM"); #endif memset(&G, 0, sizeof G); if (tcgetattr(0, &G.termios_def) < 0) exit(1); G.termios_raw = G.termios_def; cfmakeraw(&G.termios_raw); if (argc < 2) bb_show_usage(); #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN autologin = NULL; while ((opt = getopt(argc, argv, "al:")) != EOF) { switch (opt) { case 'l': autologin = optarg; break; case 'a': autologin = getenv("USER"); break; case '?': bb_show_usage(); break; } } if (optind < argc) { bb_lookup_host(&s_in, argv[optind++]); s_in.sin_port = bb_lookup_port((optind < argc) ? argv[optind++] : "telnet", "tcp", 23); if (optind < argc) bb_show_usage(); } else bb_show_usage(); #else bb_lookup_host(&s_in, argv[1]); s_in.sin_port = bb_lookup_port((argc == 3) ? argv[2] : "telnet", "tcp", 23); #endif G.netfd = xconnect(&s_in); setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one); signal(SIGINT, fgotsig); #ifdef USE_POLL ufds[0].fd = 0; ufds[1].fd = G.netfd; ufds[0].events = ufds[1].events = POLLIN; #else FD_ZERO(&readfds); FD_SET(0, &readfds); FD_SET(G.netfd, &readfds); maxfd = G.netfd + 1; #endif while (1) { #ifndef USE_POLL fd_set rfds = readfds; switch (select(maxfd, &rfds, NULL, NULL, NULL)) #else switch (poll(ufds, 2, -1)) #endif { case 0: /* timeout */ case -1: /* error, ignore and/or log something, bay go to loop */ if (G.gotsig) conescape(); else sleep(1); break; default: #ifdef USE_POLL if (ufds[0].revents) /* well, should check POLLIN, but ... */ #else if (FD_ISSET(0, &rfds)) #endif { len = read(0, G.buf, DATABUFSIZE); if (len <= 0) doexit(0); TRACE(0, ("Read con: %d\n", len)); handlenetoutput(len); } #ifdef USE_POLL if (ufds[1].revents) /* well, should check POLLIN, but ... */ #else if (FD_ISSET(G.netfd, &rfds)) #endif { len = read(G.netfd, G.buf, DATABUFSIZE); if (len <= 0) { WriteCS(1, "Connection closed by foreign host.\r\n"); doexit(1); } TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len)); handlenetinput(len); } } } }
static int xconnect_stream(const len_and_sockaddr *lsa) { int fd = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0); xconnect(fd, &lsa->sa, lsa->len); return fd; }
void nbd_client_main(void) { int sock = -1, nbd, flags; unsigned long timeout = 0; char *host=toys.optargs[0], *port=toys.optargs[1], *device=toys.optargs[2]; uint64_t devsize; // Repeat until spanked nbd = xopen(device, O_RDWR); for (;;) { int temp; // Find and connect to server sock = xconnect(xgetaddrinfo(host, port, AF_UNSPEC, SOCK_STREAM, 0, 0)); temp = 1; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &temp, sizeof(int)); // Read login data xreadall(sock, toybuf, 152); if (memcmp(toybuf, "NBDMAGIC\x00\x00\x42\x02\x81\x86\x12\x53", 16)) error_exit("bad login %s:%s", host, port); devsize = SWAP_BE64(*(uint64_t *)(toybuf+16)); flags = SWAP_BE32(*(int *)(toybuf+24)); // Set 4k block size. Everything uses that these days. ioctl(nbd, NBD_SET_BLKSIZE, 4096); ioctl(nbd, NBD_SET_SIZE_BLOCKS, devsize/4096); ioctl(nbd, NBD_CLEAR_SOCK); // If the sucker was exported read only, respect that locally. temp = (flags & 2) ? 1 : 0; xioctl(nbd, BLKROSET, &temp); if (timeout && ioctl(nbd, NBD_SET_TIMEOUT, timeout)<0) break; if (ioctl(nbd, NBD_SET_SOCK, sock) < 0) break; if (toys.optflags & FLAG_s) mlockall(MCL_CURRENT|MCL_FUTURE); // Open the device to force reread of the partition table. if ((toys.optflags & FLAG_n) || !xfork()) { char *s = strrchr(device, '/'); int i; sprintf(toybuf, "/sys/block/%.32s/pid", s ? s+1 : device); // Is it up yet? (Give it 10 seconds.) for (i=0; i<100; i++) { temp = open(toybuf, O_RDONLY); if (temp == -1) msleep(100); else { close(temp); break; } } close(open(device, O_RDONLY)); if (!(toys.optflags & FLAG_n)) exit(0); } // Daemonize here. if (daemon(0,0)) perror_exit("daemonize"); // Process NBD requests until further notice. if (ioctl(nbd, NBD_DO_IT)>=0 || errno==EBADR) break; close(sock); } // Flush queue and exit. ioctl(nbd, NBD_CLEAR_QUE); ioctl(nbd, NBD_CLEAR_SOCK); if (CFG_TOYBOX_FREE) close(nbd); }
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]); }
/************************************************************************************************** * function : according to mode, set ftp data transfer method * para : * return : {int} error code; * history : {2013.7.18 wujun} fristly be created **************************************************************************************************/ int xconnect_ftpdata(int socket_control) { if(mode) { int data_port = get_port(socket_control); if( data_port != 0 ) { ftp_server.sin_port=htons(data_port); } return(xconnect(&ftp_server, 0)); } else { int client_port, get_sock, opt, set; char cmd_buf[32]; char log[500] = {0}; struct timeval outtime; struct sockaddr_in local; char local_ip[24]; char *ip_1, *ip_2, *ip_3, *ip_4; int addr_len = sizeof(struct sockaddr); client_port = rand_local_port(); get_sock = socket(AF_INET, SOCK_STREAM, 0); if(get_sock < 0) { plog("%s", "Fun(xconnect_ftpdata):set work mode PORT and get socket error.\n"); return -1; } //set outtime for the data socket outtime.tv_sec = 1; outtime.tv_usec = 0; opt = SO_REUSEADDR; //set = setsockopt(get_sock, SOL_SOCKET,SO_RCVTIMEO, &outtime,sizeof(outtime)); if(set !=0) { memset(log, 0, 500); sprintf(log,"Fun(xconnect_ftpdata):set socket %s errno:%d\n",strerror(errno),errno); plog("%s", log); close(get_sock); return -1; } set = setsockopt(get_sock, SOL_SOCKET,SO_REUSEADDR, &opt,sizeof(opt)); if(set !=0) { memset(log, 0, 500); sprintf(log,"Fun(xconnect_ftpdata):set socket %s errno:%d\n",strerror(errno),errno); plog("%s",log); close(get_sock); return -1; } bzero(&local_host,sizeof(local_host)); local_host.sin_family = AF_INET; local_host.sin_port = htons(client_port); local_host.sin_addr.s_addr = htonl(INADDR_ANY); bzero(&local, sizeof(struct sockaddr)); while(1) { set = bind(get_sock, (struct sockaddr *)&local_host, sizeof(local_host)); if(set != 0 && errno == 11) { client_port = rand_local_port(); continue; } set = listen(get_sock, 1); if(set != 0 && errno == 11) { plog("%s","Fun(xconnect_ftpdata):listen().\n"); close(get_sock); return -1; } //get local host's ip if(getsockname(socket_control,(struct sockaddr*)&local,(socklen_t *)&addr_len) < 0) { plog("%s", "Fun(xconnect_ftpdata): get sock name error.\n"); close(get_sock); return -1; } snprintf(local_ip, sizeof(local_ip), inet_ntoa(local.sin_addr)); //change the format to the PORT command needs. local_ip[strlen(local_ip)]='\0'; ip_1 = local_ip; ip_2 = strchr(local_ip, '.'); *ip_2 = '\0'; ip_2++; ip_3 = strchr(ip_2, '.'); *ip_3 = '\0'; ip_3++; ip_4 = strchr(ip_3, '.'); *ip_4 = '\0'; ip_4++; snprintf(cmd_buf, sizeof(cmd_buf), "PORT %s,%s,%s,%s,%d,%d", ip_1, ip_2, ip_3, ip_4, client_port >> 8, client_port&0xff); if( ftp_send_cmd( cmd_buf, NULL, socket_control ) < 0 ) { plog("%s", "Fun(xconnect_ftpdata):send 'PORT' command error.\n"); close(get_sock); return -1; } if(ftp_get_reply(socket_control, NULL) != 200) { plog("%s","Fun(xconnect_ftpdata):Can not use PORT mode!Please use \"mode\" change to PASV mode.\n"); close(get_sock); return -1; } else { return get_sock; } } } }