ipsvd: use IP:PORT syntax for environment vars. Pros: 1. it's saner (matches internal libc sockaddr abstraction). 2. it's smaller. Cons: not compatible with smarden's ipsvd. Fix IPv6 define typos. Stop interpreting options in prog's args. Code size -162 bytes.
No binary (build failed)
—
(log yok)
| @@ -22,9 +22,9 @@ | |
| * | |
| * udp server is hacked up by reusing TCP code. It has the following | |
| * limitation inherent in Unix DGRAM sockets implementation: | |
| - | * - local IP address is reptrieved (using recvmsg voodoo) but |
| + | * - local IP address is retrieved (using recvmsg voodoo) but |
| * child's socket is not bound to it (bind cannot be called on | |
| - | * already bound socket). Thus you still can get outgoing packets |
| + | * already bound socket). Thus it still can emit outgoing packets |
| * with wrong sorce IP... | |
| * - don't know how to retrieve ORIGDST for udp. | |
| */ | |
| @@ -100,7 +100,7 @@ enum { | |
| static void connection_status(void) | |
| { | |
| - | /* UDP and "only 1 client max" TCP don't need this */ |
| + | /* "only 1 client max" don't need this */ |
| if (cmax > 1) | |
| printf("%s: info: status %u/%u\n", applet_name, cnum, cmax); | |
| } | |
| @@ -131,34 +131,35 @@ int tcpudpsvd_main(int argc, char **argv) | |
| const char *instructs; | |
| char *msg_per_host = NULL; | |
| unsigned len_per_host = len_per_host; /* gcc */ | |
| - | int need_hostnames, need_remote_ip; |
| - | int tcp; |
| + | #ifndef SSLSVD |
| + | struct bb_uidgid_t ugid; |
| + | #endif |
| + | bool need_hostnames, need_remote_ip, tcp; |
| + | uint16_t local_port; |
| + | char *local_hostname = NULL; |
| + | char *remote_hostname = (char*)""; /* "" used if no -h */ |
| + | char *local_addr = local_addr; /* gcc */ |
| + | char *remote_addr = remote_addr; /* gcc */ |
| + | char *remote_ip = remote_addr; /* gcc */ |
| + | len_and_sockaddr *lsa; |
| + | len_and_sockaddr local, remote; |
| + | socklen_t sa_len; |
| int pid; | |
| int sock; | |
| int conn; | |
| unsigned backlog = 20; | |
| - | len_and_sockaddr *lsa; |
| - | len_and_sockaddr local, remote; |
| - | uint16_t local_port; |
| - | uint16_t remote_port = remote_port; /* gcc */ |
| - | char *local_hostname = NULL; |
| - | char *remote_hostname = (char*)""; /* "" used if no -h */ |
| - | char *local_ip = local_ip; /* gcc */ |
| - | char *remote_ip = remote_ip; /* gcc */ |
| - | #ifndef SSLSVD |
| - | struct bb_uidgid_t ugid; |
| - | #endif |
| + | |
| tcp = (applet_name[0] == 't'); | |
| /* 3+ args, -i at most once, -p implies -h, -v is counter */ | |
| opt_complementary = "-3:?:i--i:ph:vv"; | |
| #ifdef SSLSVD | |
| - | getopt32(argc, argv, "c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:", |
| + | getopt32(argc, argv, "+c:C:i:x:u:l:Eb:hpt:vU:/:Z:K:", |
| &str_c, &str_C, &instructs, &instructs, &user, &local_hostname, | |
| &str_b, &str_t, &ssluser, &root, &cert, &key, &verbose | |
| ); | |
| #else | |
| - | getopt32(argc, argv, "c:C:i:x:u:l:Eb:hpt:v", |
| + | getopt32(argc, argv, "+c:C:i:x:u:l:Eb:hpt:v", |
| &str_c, &str_C, &instructs, &instructs, &user, &local_hostname, | |
| &str_b, &str_t, &verbose | |
| ); | |
| @@ -213,10 +214,8 @@ int tcpudpsvd_main(int argc, char **argv) | |
| if (option_mask32 & OPT_u) | |
| if (!uidgid_get(&sslugid, ssluser, 1)) { | |
| if (errno) { | |
| - | xfunc_exitcode = 100; |
| bb_perror_msg_and_die("fatal: cannot get user/group: %s", ssluser); | |
| } | |
| - | xfunc_exitcode = 111; |
| bb_error_msg_and_die("fatal: unknown user/group '%s'", ssluser); | |
| } | |
| if (!cert) cert = "./cert.pem"; | |
| @@ -244,7 +243,8 @@ int tcpudpsvd_main(int argc, char **argv) | |
| lsa = xhost2sockaddr(argv[0], local_port); | |
| sock = xsocket(lsa->sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0); | |
| setsockopt_reuseaddr(sock); | |
| - | xbind(sock, &lsa->sa, lsa->len); |
| + | sa_len = lsa->len; /* I presume sockaddr len stays the same */ |
| + | xbind(sock, &lsa->sa, sa_len); |
| if (tcp) | |
| xlisten(sock, backlog); | |
| else /* udp: needed for recv_from_to to work: */ | |
| @@ -260,9 +260,7 @@ int tcpudpsvd_main(int argc, char **argv) | |
| #endif | |
| if (verbose) { | |
| - | /* we do it only for ":port" cosmetics... oh well */ |
| - | char *addr = xmalloc_sockaddr2dotted(&lsa->sa, lsa->len); |
| - | |
| + | char *addr = xmalloc_sockaddr2dotted(&lsa->sa, sa_len); |
| printf("%s: info: listening on %s", applet_name, addr); | |
| free(addr); | |
| #ifndef SSLSVD | |
| @@ -287,10 +285,14 @@ int tcpudpsvd_main(int argc, char **argv) | |
| again2: | |
| sig_unblock(SIGCHLD); | |
| if (tcp) { | |
| - | remote.len = lsa->len; |
| + | remote.len = sa_len; |
| conn = accept(sock, &remote.sa, &remote.len); | |
| - | } else |
| - | conn = recv_from_to(sock, NULL, 0, MSG_PEEK, &remote.sa, &local.sa, lsa->len); |
| + | } else { |
| + | /* In case we won't be able to recover local below. |
| + | * Also sets port - recv_from_to is unable to do it. */ |
| + | local = *lsa; |
| + | conn = recv_from_to(sock, NULL, 0, MSG_PEEK, &remote.sa, &local.sa, sa_len); |
| + | } |
| sig_block(SIGCHLD); | |
| if (conn < 0) { | |
| if (errno != EINTR) | |
| @@ -302,7 +304,7 @@ int tcpudpsvd_main(int argc, char **argv) | |
| if (max_per_host) { | |
| /* Drop connection immediately if cur_per_host > max_per_host | |
| * (minimizing load under SYN flood) */ | |
| - | remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, lsa->len); |
| + | remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, sa_len); |
| cur_per_host = ipsvd_perhost_add(remote_ip, max_per_host, &hccp); | |
| if (cur_per_host > max_per_host) { | |
| /* ipsvd_perhost_add detected that max is exceeded | |
| @@ -319,16 +321,21 @@ int tcpudpsvd_main(int argc, char **argv) | |
| if (!tcp) { | |
| /* Voodoo magic: making udp sockets each receive its own | |
| - | * packets is not trivial */ |
| + | * 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? */ |
| - | /* Make plain write work for this socket by supplying default |
| + | /* Make plain write/send work for this socket by supplying default |
| * destination address. This also restricts incoming packets | |
| * to ones coming from this remote IP. */ | |
| - | xconnect(0, &remote.sa, lsa->len); |
| + | xconnect(0, &remote.sa, sa_len); |
| + | /* hole? at this point we have no wildcard udp socket... |
| + | * can this cause clients to get "port unreachable" icmp? */ |
| /* Open new non-connected UDP socket for further clients */ | |
| sock = xsocket(lsa->sa.sa_family, tcp ? SOCK_STREAM : SOCK_DGRAM, 0); | |
| setsockopt_reuseaddr(sock); | |
| - | xbind(sock, &lsa->sa, lsa->len); |
| + | xbind(sock, &lsa->sa, sa_len); |
| socket_want_pktinfo(sock); | |
| } | |
| @@ -355,50 +362,44 @@ int tcpudpsvd_main(int argc, char **argv) | |
| if (tcp) | |
| close(sock); | |
| - | if (need_remote_ip) { |
| - | if (!max_per_host) |
| - | remote_ip = xmalloc_sockaddr2dotted_noport(&remote.sa, lsa->len); |
| - | /* else it is already done */ |
| - | remote_port = get_nport(&remote.sa); |
| - | remote_port = ntohs(remote_port); |
| - | } |
| + | if (need_remote_ip) |
| + | remote_addr = xmalloc_sockaddr2dotted(&remote.sa, sa_len); |
| if (need_hostnames) { | |
| if (option_mask32 & OPT_h) { | |
| - | remote_hostname = xmalloc_sockaddr2host(&remote.sa, lsa->len); |
| + | remote_hostname = xmalloc_sockaddr2host_noport(&remote.sa, sa_len); |
| if (!remote_hostname) { | |
| - | bb_error_msg("warning: cannot look up hostname for %s", remote_ip); |
| + | bb_error_msg("warning: cannot look up hostname for %s", remote_addr); |
| remote_hostname = (char*)""; | |
| } | |
| } | |
| /* 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) |
| + | if (tcp) { |
| + | local.len = sa_len; |
| getsockname(0, &local.sa, &local.len); | |
| - | local_ip = xmalloc_sockaddr2dotted_noport(&local.sa, lsa->len); |
| - | local_port = get_nport(&local.sa); |
| - | local_port = ntohs(local_port); |
| + | } |
| + | local_addr = xmalloc_sockaddr2dotted(&local.sa, sa_len); |
| if (!local_hostname) { | |
| - | local_hostname = xmalloc_sockaddr2host_noport(&local.sa, lsa->len); |
| + | local_hostname = xmalloc_sockaddr2host_noport(&local.sa, sa_len); |
| if (!local_hostname) | |
| - | bb_error_msg_and_die("warning: cannot look up hostname for %s"+9, local_ip); |
| + | bb_error_msg_and_die("warning: cannot look up hostname for %s"+9, local_addr); |
| } | |
| } | |
| if (verbose) { | |
| pid = getpid(); | |
| - | printf("%s: info: pid %u from %s\n", applet_name, pid, remote_ip); |
| + | printf("%s: info: pid %u from %s\n", applet_name, pid, remote_addr); |
| if (max_per_host) | |
| printf("%s: info: concurrency %u %s %u/%u\n", | |
| applet_name, pid, remote_ip, cur_per_host, max_per_host); | |
| - | printf("%s: info: start %u %s:%s :%s:%s:%u\n", |
| + | printf("%s: info: start %u %s:%s :%s:%s\n", |
| applet_name, pid, | |
| - | local_hostname, local_ip, |
| - | remote_hostname, remote_ip, (unsigned)remote_port); |
| + | local_hostname, local_addr, |
| + | remote_hostname, remote_addr); |
| } | |
| - | // TODO: stop splitiing port# from IP? |
| if (!(option_mask32 & OPT_E)) { | |
| /* setup ucspi env */ | |
| const char *proto = tcp ? "TCP" : "UDP"; | |
| @@ -408,19 +409,14 @@ int tcpudpsvd_main(int argc, char **argv) | |
| * 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, &lsa->sa, &lsa->len) == 0) { | |
| - | char *ip = xmalloc_sockaddr2dotted_noport(&lsa->sa, lsa->len); |
| - | unsigned port = get_nport(&lsa->sa); |
| - | port = ntohs(port); |
| - | xsetenv("TCPORIGDSTIP", ip); |
| - | xsetenv("TCPORIGDSTPORT", utoa(port)); |
| - | free(ip); |
| + | char *addr = xmalloc_sockaddr2dotted(&lsa->sa, sa_len); |
| + | xsetenv("TCPORIGDSTADDR", addr); |
| + | free(addr); |
| } | |
| xsetenv("PROTO", proto); | |
| - | xsetenv_proto(proto, "LOCALIP", local_ip); |
| - | xsetenv_proto(proto, "LOCALPORT", utoa(local_port)); |
| + | xsetenv_proto(proto, "LOCALADDR", local_addr); |
| xsetenv_proto(proto, "LOCALHOST", local_hostname); | |
| - | xsetenv_proto(proto, "REMOTEIP", remote_ip); |
| - | xsetenv_proto(proto, "REMOTEPORT", utoa(remote_port)); |
| + | xsetenv_proto(proto, "REMOTEADDR", remote_addr); |
| if (option_mask32 & OPT_h) { | |
| xsetenv_proto(proto, "REMOTEHOST", remote_hostname); | |
| } | |
| @@ -18,12 +18,13 @@ socket_want_pktinfo(int fd) | |
| #ifdef IP_PKTINFO | |
| setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &const_int_1, sizeof(int)); | |
| #endif | |
| - | #ifdef IPV6_PKTINFO |
| + | #if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) |
| setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &const_int_1, sizeof(int)); | |
| #endif | |
| } | |
| + | #ifdef UNUSED |
| ssize_t | |
| send_to_from(int fd, void *buf, size_t len, int flags, | |
| const struct sockaddr *from, const struct sockaddr *to, | |
| @@ -34,8 +35,11 @@ send_to_from(int fd, void *buf, size_t len, int flags, | |
| #else | |
| struct iovec iov[1]; | |
| struct msghdr msg; | |
| - | char cbuf[LSA_SIZEOF_SA]; |
| - | /* actually, max(sizeof(in_pktinfo),sizeof(in6_pktinfo)) */ |
| + | char cbuf[sizeof(struct in_pktinfo) |
| + | #if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) |
| + | | sizeof(struct in6_pktinfo) /* (a|b) is poor man's max(a,b) */ |
| + | #endif |
| + | ]; |
| struct cmsghdr* cmsgptr; | |
| if (from->sa_family != AF_INET | |
| @@ -73,11 +77,11 @@ send_to_from(int fd, void *buf, size_t len, int flags, | |
| /* pktptr->ipi_ifindex = 0; -- already done by memset(cbuf...) */ | |
| pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr; | |
| } | |
| - | #if ENABLE_FEATURE_IPV6 && defined(IP6_PKTINFO) |
| + | #if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) |
| else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) { | |
| struct in6_pktinfo *pktptr; | |
| cmsgptr->cmsg_level = IPPROTO_IPV6; | |
| - | cmsgptr->cmsg_type = IP6_PKTINFO; |
| + | cmsgptr->cmsg_type = IPV6_PKTINFO; |
| cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); | |
| pktptr = (struct in6_pktinfo *)(CMSG_DATA(cmsgptr)); | |
| /* pktptr->ipi6_ifindex = 0; -- already done by memset(cbuf...) */ | |
| @@ -87,8 +91,12 @@ send_to_from(int fd, void *buf, size_t len, int flags, | |
| return sendmsg(fd, &msg, flags); | |
| #endif | |
| } | |
| + | #endif /* UNUSED */ |
| - | /* NB: this will never set port# in *to! */ |
| + | /* NB: this will never set port# in 'to'! |
| + | * _Only_ IP/IPv6 address part of 'to' is _maybe_ modified. |
| + | * Typical usage is to preinit it with "default" value |
| + | * before calling recv_from_to(). */ |
| ssize_t | |
| recv_from_to(int fd, void *buf, size_t len, int flags, | |
| struct sockaddr *from, struct sockaddr *to, | |
| @@ -123,7 +131,6 @@ recv_from_to(int fd, void *buf, size_t len, int flags, | |
| return recv_length; | |
| /* Here we try to retrieve destination IP and memorize it */ | |
| - | memset(to, 0, sa_size); |
| for (cmsgptr = CMSG_FIRSTHDR(&msg); | |
| cmsgptr != NULL; | |
| cmsgptr = CMSG_NXTHDR(&msg, cmsgptr) | |
| @@ -138,9 +145,9 @@ recv_from_to(int fd, void *buf, size_t len, int flags, | |
| #undef pktinfo | |
| break; | |
| } | |
| - | #if ENABLE_FEATURE_IPV6 && defined(IP6_PKTINFO) |
| + | #if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO) |
| if (cmsgptr->cmsg_level == IPPROTO_IPV6 | |
| - | && cmsgptr->cmsg_type == IP6_PKTINFO |
| + | && cmsgptr->cmsg_type == IPV6_PKTINFO |
| ) { | |
| #define pktinfo(cmsgptr) ( (struct in6_pktinfo*)(CMSG_DATA(cmsgptr)) ) | |
| to->sa_family = AF_INET6; | |