diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2023-11-18 04:17:07 +0000 |
---|---|---|
committer | Laurent Bercot <ska@appnovation.com> | 2023-11-18 04:17:07 +0000 |
commit | 06b1f4f397d53e9a4c9abe4c8c4c20a7240e7736 (patch) | |
tree | 05b93d967f6a946a7e0e2395399405c4ec12e3a9 /src | |
parent | df6d3fae47a106b70dd9e073d0e60989cd182f79 (diff) | |
download | s6-networking-06b1f4f397d53e9a4c9abe4c8c4c20a7240e7736.tar.xz |
/etc/hosts support for s6-tcpclient and s6-tcpserver-access
Signed-off-by: Laurent Bercot <ska@appnovation.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/conn-tools/s6-tcpclient.c | 91 | ||||
-rw-r--r-- | src/conn-tools/s6-tcpserver-access.c | 78 | ||||
-rw-r--r-- | src/tls/s6-tlsclient.c | 9 | ||||
-rw-r--r-- | src/tls/s6-tlsserver.c | 9 |
4 files changed, 136 insertions, 51 deletions
diff --git a/src/conn-tools/s6-tcpclient.c b/src/conn-tools/s6-tcpclient.c index ec31cf9..0224abd 100644 --- a/src/conn-tools/s6-tcpclient.c +++ b/src/conn-tools/s6-tcpclient.c @@ -21,13 +21,15 @@ #include <s6-networking/ident.h> + /* XXX: this file is super ugly and full of tech debt */ + #ifdef SKALIBS_IPV6_ENABLED -# define USAGE "s6-tcpclient [ -q | -Q | -v ] [ -4 | -6 ] [ -d | -D ] [ -r | -R ] [ -h | -H ] [ -n | -N ] [ -t timeoutinfo ] [ -l localname ] [ -T timeoutconn ] [ -i localip ] [ -p localport ] host port prog..." -# define TFLAGS_DEFAULT { 0, 0, { 2, 58 }, IP46_ZERO, 0, 1, 0, 0, 1, 0, 1, 1 } +# define USAGE "s6-tcpclient [ -q | -Q | -v ] [ -4 | -6 ] [ -d | -D ] [ -r | -R ] [ -h ] [ -H ] [ -n | -N ] [ -t timeoutinfo ] [ -l localname ] [ -T timeoutconn ] [ -i localip ] [ -p localport ] host port prog..." +# define TFLAGS_DEFAULT { 0, 0, { 2, 58 }, IP46_ZERO, 0, 1, 0, 0, 1, 0, 1, 0, 1 } # define OPTSTRING "qQv46dDrRhHnNt:l:T:i:p:" #else -# define USAGE "s6-tcpclient [ -q | -Q | -v ] [ -d | -D ] [ -r | -R ] [ -h | -H ] [ -n | -N ] [ -t timeoutinfo ] [ -l localname ] [ -T timeoutconn ] [ -i localip ] [ -p localport ] host port prog..." -# define TFLAGS_DEFAULT { 0, 0, { 2, 58 }, IP46_ZERO, 0, 1, 1, 0, 1, 1 } +# define USAGE "s6-tcpclient [ -q | -Q | -v ] [ -d | -D ] [ -r | -R ] [ -h ] [ -H ] [ -n | -N ] [ -t timeoutinfo ] [ -l localname ] [ -T timeoutconn ] [ -i localip ] [ -p localport ] host port prog..." +# define TFLAGS_DEFAULT { 0, 0, { 2, 58 }, IP46_ZERO, 0, 1, 1, 0, 1, 0, 1 } # define OPTSTRING "qQvdDrRhHnNt:l:T:i:p:" #endif @@ -52,6 +54,7 @@ struct tflags_s unsigned int delay : 1 ; unsigned int remoteinfo : 1 ; unsigned int remotehost : 1 ; + unsigned int hosts : 1 ; unsigned int qualif : 1 ; } ; @@ -60,7 +63,7 @@ static tain deadline ; int main (int argc, char const *const *argv) { int s ; - int localip = 0; + int haslocalip = 0 ; tflags flags = TFLAGS_DEFAULT ; uint16_t remoteport ; PROG = "s6-tcpclient" ; @@ -83,7 +86,7 @@ int main (int argc, char const *const *argv) case 'D' : flags.delay = 0 ; break ; case 'r' : flags.remoteinfo = 1 ; break ; case 'R' : flags.remoteinfo = 0 ; break ; - case 'h' : flags.remotehost = 1 ; break ; + case 'h' : flags.hosts = 1 ; break ; case 'H' : flags.remotehost = 0 ; break ; case 'n' : flags.qualif = 1 ; break ; case 'N' : flags.qualif = 0 ; break ; @@ -102,7 +105,7 @@ int main (int argc, char const *const *argv) if (!uint0_scan(l.arg + n + 1, &flags.timeoutconn[1])) usage() ; break ; } - case 'i' : if (!ip46_scan(l.arg, &flags.localip)) usage() ; localip = 1 ; break ; + case 'i' : if (!ip46_scan(l.arg, &flags.localip)) usage() ; haslocalip = 1 ; break ; case 'p' : if (!uint160_scan(l.arg, &flags.localport)) usage() ; break ; default : usage() ; } @@ -118,7 +121,10 @@ int main (int argc, char const *const *argv) tain_now_set_stopwatch_g() ; if (flags.timeout) tain_addsec_g(&deadline, flags.timeout) ; else tain_add_g(&deadline, &tain_infinite_relative) ; - if (!s6dns_init()) strerr_diefu1sys(111, "init DNS") ; + + if (flags.remotehost || !flags.localname) + if (!s6dns_init_options(flags.hosts)) strerr_diefu1sys(111, "init DNS") ; + { ip46 ip[2][MAXIP] ; unsigned int j = 0 ; @@ -162,7 +168,13 @@ int main (int argc, char const *const *argv) { genalloc ips = STRALLOC_ZERO ; size_t i = 0 ; - if (s6dns_resolve_aaaaa_g(&ips, argv[0], strlen(argv[0]), flags.qualif, &deadline) <= 0) + int r = 0 ; + if (flags.hosts) + { + r = flags.qualif ? s6dns_hosts_aaaaa_q(argv[0], &ips) : s6dns_hosts_aaaaa_noq(argv[0], &ips) ; + if (r == -1) strerr_diefu3sys(111, "look up ", argv[0], " in hosts database") ; + } + if (!r && s6dns_resolve_aaaaa_g(&ips, argv[0], strlen(argv[0]), flags.qualif, &deadline) <= 0) strerr_diefu4x(111, "resolve ", argv[0], ": ", s6dns_constants_error_str(errno)) ; n[0] = genalloc_len(ip46, &ips) ; if (n[0] >= MAXIP) n[0] = MAXIP ; @@ -174,15 +186,19 @@ int main (int argc, char const *const *argv) { char ip6[MAXIP << 4] ; if (ip6_scanlist(ip6, MAXIP, argv[0], &n[0])) - { - size_t i = 0 ; - for (; i < n[0] ; i++) ip46_from_ip6(&ip[0][i], ip6 + (i << 4)) ; - } + for (size_t i = 0 ; i < n[0] ; i++) + ip46_from_ip6(&ip[0][i], ip6 + (i << 4)) ; else { stralloc ip6s = STRALLOC_ZERO ; size_t i = 0 ; - if (s6dns_resolve_aaaa_g(&ip6s, argv[0], strlen(argv[0]), flags.qualif, &deadline) <= 0) + int r = 0 ; + if (flags.hosts) + { + r = flags.qualif ? s6dns_hosts_aaaa_q(argv[0], &ip6s) : s6dns_hosts_aaaa_noq(argv[0], &ip6s) ; + if (r == -1) strerr_diefu3sys(111, "look up ", argv[0], " in hosts database") ; + } + if (!r && s6dns_resolve_aaaa_g(&ip6s, argv[0], strlen(argv[0]), flags.qualif, &deadline) <= 0) strerr_diefu4x(111, "resolve ", argv[0], ": ", s6dns_constants_error_str(errno)) ; n[0] = ip6s.len >> 4 ; if (n[0] >= MAXIP) n[0] = MAXIP ; @@ -195,15 +211,19 @@ int main (int argc, char const *const *argv) { char ip4[MAXIP << 2] ; if (ip4_scanlist(ip4, MAXIP, argv[0], &n[0])) - { - size_t i = 0 ; - for (; i < n[0] ; i++) ip46_from_ip4(&ip[0][i], ip4 + (i << 2)) ; - } + for (size_t i = 0 ; i < n[0] ; i++) + ip46_from_ip4(&ip[0][i], ip4 + (i << 2)) ; else { stralloc ip4s = STRALLOC_ZERO ; size_t i = 0 ; - if (s6dns_resolve_a_g(&ip4s, argv[0], strlen(argv[0]), flags.qualif, &deadline) <= 0) + int r = 0 ; + if (flags.hosts) + { + r = flags.qualif ? s6dns_hosts_a_q(argv[0], &ip4s) : s6dns_hosts_a_noq(argv[0], &ip4s) ; + if (r == -1) strerr_diefu3sys(111, "look up ", argv[0], " in hosts database") ; + } + if (!r && s6dns_resolve_a_g(&ip4s, argv[0], strlen(argv[0]), flags.qualif, &deadline) <= 0) strerr_diefu4x(111, "resolve ", argv[0], ": ", s6dns_constants_error_str(errno)) ; n[0] = ip4s.len >> 2 ; if (n[0] >= MAXIP) n[0] = MAXIP ; @@ -228,7 +248,7 @@ int main (int argc, char const *const *argv) { tain localdeadline ; #ifdef SKALIBS_IPV6_ENABLED - if(!localip) flags.localip.is6 = ip46_is6(&ip[j][i]); + if (!haslocalip) flags.localip.is6 = ip46_is6(&ip[j][i]) ; #endif s = socket_tcp46(ip46_is6(&flags.localip)); if (s < 0) strerr_diefu1sys(111, "create socket") ; @@ -285,6 +305,37 @@ int main (int argc, char const *const *argv) if (!env_mexec("TCPLOCALHOST", flags.localname)) dienomem() ; } + if (flags.hosts) + { + stralloc sa = STRALLOC_ZERO ; + genalloc ga = GENALLOC_ZERO ; + if (!flags.localname) + { + int r = s6dns_hosts_name(flags.localip.ip, &sa, &ga, ip46_is6(&flags.localip)) ; + if (r == -1) strerr_diefu3sys(111, "look up name for ", "local", " ip in hosts database") ; + if (r) + { + if (!env_mexec("TCPLOCALHOST", sa.s + genalloc_s(size_t, &ga)[0])) dienomem() ; + genalloc_setlen(size_t, &ga, 0) ; + sa.len = 0 ; + flags.localname = "" ; + } + } + if (flags.remotehost) + { + int r = s6dns_hosts_name(remoteip.ip, &sa, &ga, ip46_is6(&remoteip)) ; + if (r == -1) strerr_diefu3sys(111, "look up name for ", "remote", " ip in hosts database") ; + if (r) + { + if (!env_mexec("TCPREMOTEHOST", sa.s + genalloc_s(size_t, &ga)[0])) dienomem() ; + flags.remotehost = 0 ; + } + } + genalloc_free(size_t, &ga) ; + stralloc_free(&sa) ; + } + + /* DNS resolution for TCPLOCALHOST and TCPREMOTEHOST */ if (!flags.localname || flags.remotehost) diff --git a/src/conn-tools/s6-tcpserver-access.c b/src/conn-tools/s6-tcpserver-access.c index e8c868a..10a9c5b 100644 --- a/src/conn-tools/s6-tcpserver-access.c +++ b/src/conn-tools/s6-tcpserver-access.c @@ -33,12 +33,13 @@ #include <execline/config.h> #endif -#define USAGE "s6-tcpserver-access [ -v verbosity ] [ -W | -w ] [ -D | -d ] [ -H | -h ] [ -R | -r ] [ -P | -p ] [ -l localname ] [ -B banner ] [ -t timeout ] [ -i rulesdir | -x rulesfile ] prog..." + /* XXX: this file is super ugly and full of tech debt */ + +#define USAGE "s6-tcpserver-access [ -v verbosity ] [ -W | -w ] [ -D | -d ] [ -H ] [ -h ] [ -R | -r ] [ -P | -p ] [ -l localname ] [ -B banner ] [ -t timeout ] [ -i rulesdir | -x rulesfile ] prog..." #define dieusage() strerr_dieusage(100, USAGE) #define dienomem() strerr_diefu1sys(111, "update environment") #define X() strerr_dief1x(101, "internal inconsistency. Please submit a bug-report.") - static void logit (pid_t pid, ip46 const *ip, int h) { char fmtpid[PID_FMT] ; @@ -75,7 +76,7 @@ int main (int argc, char const *const *argv) size_t protolen ; s6_accessrules_result_t accepted ; ip46 remoteip, localip ; - int flagfatal = 1, flagnodelay = 0, flagdnslookup = 1, + int flagfatal = 1, flagnodelay = 0, flagdnslookup = 1, flaghosts = 0, flagident = 0, flagparanoid = 0, e = 0 ; uint16_t remoteport, localport ; PROG = "s6-tcpserver-access" ; @@ -93,7 +94,7 @@ int main (int argc, char const *const *argv) case 'D' : flagnodelay = 1 ; break ; case 'd' : flagnodelay = 0 ; break ; case 'H' : flagdnslookup = 0 ; break ; - case 'h' : flagdnslookup = 1 ; break ; + case 'h' : flaghosts = 1 ; break ; case 'R' : flagident = 0 ; break ; case 'r' : flagident = 1 ; break ; case 'P' : flagparanoid = 0 ; break ; @@ -228,11 +229,13 @@ int main (int argc, char const *const *argv) } else { + stralloc sa = STRALLOC_ZERO ; + genalloc ga = GENALLOC_ZERO ; tain infinite ; s6dns_dpag_t data[2] = { S6DNS_DPAG_ZERO, S6DNS_DPAG_ZERO } ; s6dns_resolve_t blob[2] ; char remotebuf[256] ; - unsigned int remotelen = 0 ; + size_t remotelen = 0 ; char tcplocalhost[(protolen << 1) + 21] ; char *tcpremotehost = tcplocalhost + protolen + 10 ; memcpy(tcplocalhost, proto, protolen) ; @@ -241,7 +244,7 @@ int main (int argc, char const *const *argv) memcpy(tcpremotehost + protolen, "REMOTEHOST", 11) ; tain_add_g(&infinite, &tain_infinite_relative) ; - if (!s6dns_init()) + if (!s6dns_init_options(flaghosts)) { if (verbosity >= 2) strerr_warnwu1sys("init DNS") ; if (flagfatal) @@ -250,6 +253,33 @@ int main (int argc, char const *const *argv) goto reject ; } } + if (flaghosts) + { + int r = s6dns_hosts_name(remoteip.ip, &sa, &ga, ip46_is6(&remoteip)) ; + if (r == -1) + { + if (verbosity >= 2) strerr_warnwu3sys("look up ", "remote", " ip in hosts database") ; + if (flagfatal) { e = 111 ; goto reject ; } + } + if (r) + { + remotelen = strlen(sa.s + genalloc_s(size_t, &ga)[0]) ; + if (remotelen > 255) remotelen = 255 ; + memcpy(remotebuf, sa.s + genalloc_s(size_t, &ga)[0], remotelen + 1) ; + genalloc_setlen(size_t, &ga, 0) ; + sa.len = 0 ; + } + if (!localname) + { + r = s6dns_hosts_name(localip.ip, &sa, &ga, ip46_is6(&localip)) ; + if (r == -1) + { + if (verbosity >= 2) strerr_warnwu3sys("look up ", "local", " ip in hosts database") ; + if (flagfatal) { e = 111 ; goto reject ; } + } + if (r) localname = sa.s + genalloc_s(size_t, &ga)[0] ; + } + } if (localname) { if (!env_addmodif(&modifs, tcplocalhost, localname)) dienomem() ; @@ -265,15 +295,18 @@ int main (int argc, char const *const *argv) blob[0].options = S6DNS_O_RECURSIVE ; data[0].rtype = S6DNS_T_PTR ; } - s6dns_domain_arpafromip46(&blob[1].q, &remoteip) ; - s6dns_domain_encode(&blob[1].q) ; - blob[1].qtype = S6DNS_T_PTR ; - blob[1].deadline = deadline ; - blob[1].parsefunc = &s6dns_message_parse_answer_domain ; - blob[1].data = &data[1] ; - blob[1].options = S6DNS_O_RECURSIVE ; - data[1].rtype = S6DNS_T_PTR ; - if (!s6dns_resolven_parse_g(blob + !!localname, 1 + !localname, &infinite)) + if (!remotelen) + { + s6dns_domain_arpafromip46(&blob[1].q, &remoteip) ; + s6dns_domain_encode(&blob[1].q) ; + blob[1].qtype = S6DNS_T_PTR ; + blob[1].deadline = deadline ; + blob[1].parsefunc = &s6dns_message_parse_answer_domain ; + blob[1].data = &data[1] ; + blob[1].options = S6DNS_O_RECURSIVE ; + data[1].rtype = S6DNS_T_PTR ; + } + if (!localname && !remotelen && !s6dns_resolven_parse_g(blob + !!localname, !localname + !remotelen, &infinite)) { if (verbosity >= 3) strerr_warnwu2x("resolve IP addresses: ", s6dns_constants_error_str(errno)) ; if (flagfatal) @@ -304,7 +337,7 @@ int main (int argc, char const *const *argv) if (!env_addmodif(&modifs, tcplocalhost, s)) dienomem() ; } } - if (!blob[1].status) + if (!remotelen && !blob[1].status) { if (genalloc_len(s6dns_domain_t, &data[1].ds)) { @@ -339,6 +372,8 @@ int main (int argc, char const *const *argv) } } if (!env_addmodif(&modifs, tcpremotehost, remotelen ? remotebuf : 0)) dienomem() ; + + if (remotelen && (accepted == S6_ACCESSRULES_NOTFOUND)) { switch (rulestype) @@ -386,13 +421,6 @@ int main (int argc, char const *const *argv) xmexec_m(argv, params.env.s, params.env.len) ; reject: - if (verbosity >= 2) - { - char fmtpid[PID_FMT] ; - char fmtip[IP46_FMT] ; - fmtip[ip46_fmt(fmtip, &remoteip)] = 0 ; - fmtpid[pid_fmt(fmtpid, getpid())] = 0 ; - strerr_dief5x(e, "reject", " pid ", fmtpid, " ip ", fmtip) ; - } - else return e ; + if (verbosity >= 2) log_deny(getpid(), &remoteip) ; + return e ; } diff --git a/src/tls/s6-tlsclient.c b/src/tls/s6-tlsclient.c index 888c11a..da84aa8 100644 --- a/src/tls/s6-tlsclient.c +++ b/src/tls/s6-tlsclient.c @@ -12,7 +12,7 @@ #include <s6-networking/config.h> #define USAGE "s6-tlsclient [ options ] host port prog...\n" \ -"s6-tcpclient options: [ -q | -Q | -v ] [ -4 | -6 ] [ -d | -D ] [ -r | -R ] [ -h | -H ] [ -n | -N ] [ -t timeout ] [ -l localname ] [ -T timeoutconn ] [ -i localip ] [ -p localport ]\n" \ +"s6-tcpclient options: [ -q | -Q | -v ] [ -4 | -6 ] [ -d | -D ] [ -r | -R ] [ -h ] [ -H ] [ -n | -N ] [ -t timeout ] [ -l localname ] [ -T timeoutconn ] [ -i localip ] [ -p localport ]\n" \ "s6-tlsc options: [ -S | -s ] [ -J | -j ] [ -Y | -y ] [ -K timeout ] [ -k servername ] [ -Z | -z ]" #define dieusage() strerr_dieusage(100, USAGE) @@ -33,6 +33,7 @@ struct options_s unsigned int flag6 : 1 ; unsigned int flagD : 1 ; unsigned int flagH : 1 ; + unsigned int flagh : 1 ; unsigned int flagr : 1 ; unsigned int flagN : 1 ; unsigned int flagS : 1 ; @@ -57,6 +58,7 @@ struct options_s .flag6 = 0, \ .flagD = 0, \ .flagH = 0, \ + .flagh = 0, \ .flagr = 0, \ .flagN = 0, \ .flagS = 0, \ @@ -86,7 +88,7 @@ int main (int argc, char const *const *argv) case 'D' : o.flagD = 1 ; break ; case 'd' : o.flagD = 0 ; break ; case 'H' : o.flagH = 1 ; break ; - case 'h' : o.flagH = 0 ; break ; + case 'h' : o.flagh = 1 ; break ; case 'R' : o.flagr = 0 ; break ; case 'r' : o.flagr = 1 ; break ; case 'n' : o.flagN = 0 ; break ; @@ -137,13 +139,14 @@ int main (int argc, char const *const *argv) size_t pos = 0 ; unsigned int m = 0 ; char fmt[UINT_FMT * 4 + UINT16_FMT + IP46_FMT] ; - char const *newargv[32 + argc] ; + char const *newargv[33 + argc] ; newargv[m++] = S6_NETWORKING_BINPREFIX "s6-tcpclient" ; if (o.verbosity != 1) newargv[m++] = o.verbosity ? "-v" : "-q" ; if (o.flag4) newargv[m++] = "-4" ; if (o.flag6) newargv[m++] = "-6" ; if (o.flagD) newargv[m++] = "-D" ; if (o.flagH) newargv[m++] = "-H" ; + if (o.flagh) newargv[m++] = "-h" ; if (o.flagr) newargv[m++] = "-r" ; if (o.flagN) newargv[m++] = "-N" ; if (o.timeout) diff --git a/src/tls/s6-tlsserver.c b/src/tls/s6-tlsserver.c index 0c38600..5f9c7dd 100644 --- a/src/tls/s6-tlsserver.c +++ b/src/tls/s6-tlsserver.c @@ -14,7 +14,7 @@ #define USAGE "s6-tlsserver [ options ] ip port prog...\n" \ "s6-tcpserver options: [ -q | -Q | -v ] [ -1 ] [ -c maxconn ] [ -C localmaxconn ] [ -b backlog ] [ -G gidlist ] [ -g gid ] [ -u uid ] [ -U ]\n" \ -"s6-tcpserver-access options: [ -W | -w ] [ -D | -d ] [ -H | -h ] [ -R | -r ] [ -P | -p ] [ -l localname ] [ -B banner ] [ -t timeout ] [ -i rulesdir | -x rulesfile ]\n" \ +"s6-tcpserver-access options: [ -W | -w ] [ -D | -d ] [ -H ] [ -h ] [ -R | -r ] [ -P | -p ] [ -l localname ] [ -B banner ] [ -t timeout ] [ -i rulesdir | -x rulesfile ]\n" \ "s6-tlsd options: [ -S | -s ] [ -J | -j ] [ -Y | -y ] [ -K timeout ] [ -Z | -z ] [ -k snilevel ]" #define dieusage() strerr_dieusage(100, USAGE) @@ -41,6 +41,7 @@ struct options_s unsigned int flagw : 1 ; unsigned int flagD : 1 ; unsigned int flagH : 1 ; + unsigned int flagh : 1 ; unsigned int flagr : 1 ; unsigned int flagp : 1 ; unsigned int rulesx : 1 ; @@ -72,6 +73,7 @@ struct options_s .flagw = 0, \ .flagD = 0, \ .flagH = 0, \ + .flagh = 0, \ .flagr = 0, \ .flagp = 0, \ .rulesx = 0, \ @@ -111,7 +113,7 @@ int main (int argc, char const *const *argv) case 'D' : o.flagD = 1 ; break ; case 'd' : o.flagD = 0 ; break ; case 'H' : o.flagH = 1 ; break ; - case 'h' : o.flagH = 0 ; break ; + case 'h' : o.flagh = 1 ; break ; case 'R' : o.flagr = 0 ; break ; case 'r' : o.flagr = 1 ; break ; case 'P' : o.flagp = 0 ; break ; @@ -142,7 +144,7 @@ int main (int argc, char const *const *argv) size_t pos = 0 ; unsigned int m = 0 ; char fmt[UINT_FMT * 6 + UID_FMT + GID_FMT * (NGROUPS_MAX + 1)] ; - char const *newargv[50 + argc] ; + char const *newargv[51 + argc] ; int doaccess = o.flagw || o.flagD || !o.flagH || o.flagr || o.flagp || o.localname || o.banner || o.timeout || o.rules ; newargv[m++] = S6_NETWORKING_BINPREFIX "s6-tcpserver" ; if (o.verbosity != 1) @@ -187,6 +189,7 @@ int main (int argc, char const *const *argv) if (o.flagw) newargv[m++] = "-w" ; if (o.flagD) newargv[m++] = "-D" ; if (o.flagH) newargv[m++] = "-H" ; + if (o.flagh) newargv[m++] = "-h" ; if (o.flagr) newargv[m++] = "-r" ; if (o.flagp) newargv[m++] = "-p" ; if (o.localname) |