Add -a passthrough option

main
cel 7 years ago
parent 217595e9b8
commit 25b777fa9d

@ -16,8 +16,10 @@ sudo make install
## Usage ## Usage
```sh ```sh
sbotc [-j] [-T] [-n] [-c <cap>] [-s <host>] [-p <port>] [-u <socket_path>] [-k <key>] [-K <keypair_seed>] sbotc [-j] [-T]
[-t <type>] <method> [<argument>...] [ -n | [-c <cap>] [-k <key>] [-K <keypair_seed>] ]
[ [-s <host>] [-p <port>] [ -4 | -6 ] | [-u <socket_path>] ]
[ -a | [-t <type>] <method> [<argument>...] ]
``` ```
Arguments must be explicitly JSON-encoded. Arguments must be explicitly JSON-encoded.

@ -9,6 +9,7 @@
.Nm .Nm
.Op Fl j .Op Fl j
.Op Fl T .Op Fl T
.Op Fl a
. .
.Oo .Oo
.Fl n .Fl n
@ -30,9 +31,13 @@
.Op Fl u Ar socket_path .Op Fl u Ar socket_path
.Oc .Oc
. .
.Oo
.Fl a
|
.Op Fl t Ar type .Op Fl t Ar type
.Ar method .Ar method
.Op Ar argument ... .Op Ar argument ...
.Oc
.Sh DESCRIPTION .Sh DESCRIPTION
Connect to a scuttlebot/secret-stack server, and call a method on it, with Connect to a scuttlebot/secret-stack server, and call a method on it, with
standard I/O. standard I/O.
@ -44,6 +49,9 @@ Send stdin data as JSON.
Test using shs1-testsuite protocol. Instead of connecting to a server and running Test using shs1-testsuite protocol. Instead of connecting to a server and running
a command, connect to stdio. On successful handshake, output concatenation of a command, connect to stdio. On successful handshake, output concatenation of
the encryption key, encryption nonce, decryption key and decryption nonce. the encryption key, encryption nonce, decryption key and decryption nonce.
.It Fl a
Passthrough mode. Instead of making a muxrpc call, pass through the box-stream
to stdio.
.It Fl n .It Fl n
Noauth mode. Skip secret-handshake authentication and box-stream encryption. Noauth mode. Skip secret-handshake authentication and box-stream encryption.
This option makes the This option makes the

@ -106,7 +106,7 @@ static void usage() {
fputs("usage: sbotc [-j] [-T]\n" fputs("usage: sbotc [-j] [-T]\n"
" [ -n | [-c <cap>] [-k <key>] [-K <keypair_seed>] ]\n" " [ -n | [-c <cap>] [-k <key>] [-K <keypair_seed>] ]\n"
" [ [-s <host>] [-p <port>] [ -4 | -6 ] | [-u <socket_path>] ]\n" " [ [-s <host>] [-p <port>] [ -4 | -6 ] | [-u <socket_path>] ]\n"
" [-t <type>] <method> [<argument>...]\n", stderr); " [ -a | [-t <type>] <method> [<argument>...] ]\n", stderr);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -176,6 +176,16 @@ static int read_all(int fd, void *buf, size_t count) {
return 0; return 0;
} }
static int read_some(int fd, unsigned char *buf, size_t *lenp) {
ssize_t nbytes;
do nbytes = read(fd, buf, *lenp);
while (nbytes < 0 && errno == EINTR);
if (nbytes == 0) { errno = EPIPE; return -1; }
if (nbytes < 0) return -1;
*lenp = nbytes;
return 0;
}
static int write_all(int fd, const void *buf, size_t count) { static int write_all(int fd, const void *buf, size_t count) {
ssize_t nbytes; ssize_t nbytes;
while (count > 0) { while (count > 0) {
@ -485,12 +495,20 @@ static void bs_end(struct boxs *bs) {
if (!bs->noauth) { if (!bs->noauth) {
bs_write_end_box(bs); bs_write_end_box(bs);
} }
shutdown(bs->s, SHUT_WR);
} }
static int bs_read_packet(struct boxs *bs, void *buf, size_t *lenp) { static int bs_read_packet(struct boxs *bs, void *buf, size_t *lenp) {
int rc;
if (bs->noauth) {
rc = read_some(bs->s, buf, lenp);
if (rc < 0 && errno == EPIPE) return -1;
if (rc < 0) err(1, "failed to read packet data");
return 0;
}
unsigned char boxed_header[34]; unsigned char boxed_header[34];
struct boxs_header header; struct boxs_header header;
int rc = read_all(bs->s, boxed_header, 34); rc = read_all(bs->s, boxed_header, 34);
if (rc < 0 && errno == EPIPE) errx(1, "unexpected end of parent stream"); if (rc < 0 && errno == EPIPE) errx(1, "unexpected end of parent stream");
if (rc < 0) err(1, "failed to read boxed packet header"); if (rc < 0) err(1, "failed to read boxed packet header");
rc = crypto_secretbox_open_easy((unsigned char *)&header, boxed_header, 34, bs->rx_nonce, bs->decrypt_key); rc = crypto_secretbox_open_easy((unsigned char *)&header, boxed_header, 34, bs->rx_nonce, bs->decrypt_key);
@ -531,6 +549,18 @@ static int bs_read(struct boxs *bs, char *buf, size_t len) {
return 0; return 0;
} }
static enum stream_state bs_read_out_1(struct boxs *bs, int fd) {
size_t buf[4096];
size_t len = sizeof(buf);
int rc;
rc = bs_read_packet(bs, buf, &len);
if (rc < 0 && errno == EPIPE) return stream_state_ended_ok;
if (rc < 0) return stream_state_ended_error;
rc = write_all(fd, buf, len);
if (rc < 0) return stream_state_ended_error;
return stream_state_open;
}
static int bs_read_out(struct boxs *bs, int fd, size_t len) { static int bs_read_out(struct boxs *bs, int fd, size_t len) {
size_t chunk; size_t chunk;
char buf[4096]; char buf[4096];
@ -578,6 +608,18 @@ static void bs_write(struct boxs *bs, const unsigned char *buf, size_t len) {
} }
} }
static enum stream_state bs_write_in_1(struct boxs *bs, int fd) {
unsigned char buf[4096];
ssize_t sz = read(fd, buf, sizeof(buf));
if (sz < 0) err(1, "read");
if (sz == 0) {
bs_end(bs);
return stream_state_ended_ok;
}
bs_write(bs, buf, sz);
return stream_state_open;
}
static void ps_write(struct boxs *bs, const char *data, size_t len, enum pkt_type type, int req_id, bool stream, bool end) { static void ps_write(struct boxs *bs, const char *data, size_t len, enum pkt_type type, int req_id, bool stream, bool end) {
size_t out_len = 9 + len; size_t out_len = 9 + len;
unsigned char out_buf[out_len]; unsigned char out_buf[out_len];
@ -619,6 +661,29 @@ static void muxrpc_call(struct boxs *bs, const char *method, const char *argumen
ps_write(bs, req, reqlen, pkt_type_json, req_id, !is_request, false); ps_write(bs, req, reqlen, pkt_type_json, req_id, !is_request, false);
} }
static int bs_passthrough(struct boxs *bs, int infd, int outfd) {
int rc;
fd_set rd;
int sfd = bs->s;
int maxfd = infd > sfd ? infd : sfd;
enum stream_state in = stream_state_open;
enum stream_state out = stream_state_open;
while (out == stream_state_open
|| (in == stream_state_open && out != stream_state_ended_error)) {
FD_ZERO(&rd);
if (in == stream_state_open) FD_SET(infd, &rd);
if (out == stream_state_open) FD_SET(sfd, &rd);
rc = select(maxfd + 1, &rd, 0, 0, NULL);
if (rc < 0) err(1, "select");
if (FD_ISSET(infd, &rd)) in = bs_write_in_1(bs, infd);
if (FD_ISSET(sfd, &rd)) out = bs_read_out_1(bs, outfd);
}
return in == stream_state_ended_ok && out == stream_state_ended_ok ? 0 :
in == stream_state_ended_error || out == stream_state_ended_error ? 2 : 1;
}
static void ps_reject(struct boxs *bs, size_t len, int32_t req, enum pkt_flags flags) { static void ps_reject(struct boxs *bs, size_t len, int32_t req, enum pkt_flags flags) {
// ignore the packet. if this is a request, the substream on the other end // ignore the packet. if this is a request, the substream on the other end
// will just have to wait until the rpc connection closes. // will just have to wait until the rpc connection closes.
@ -866,7 +931,7 @@ int main(int argc, char *argv[]) {
const char *keypair_seed_str = NULL; const char *keypair_seed_str = NULL;
const char *host = NULL; const char *host = NULL;
const char *port = "8008"; const char *port = "8008";
const char *typestr = NULL, *methodstr; const char *typestr = NULL, *methodstr = NULL;
const char *shs_cap_key_str = NULL; const char *shs_cap_key_str = NULL;
const char *socket_path = NULL; const char *socket_path = NULL;
size_t argument_len; size_t argument_len;
@ -887,6 +952,7 @@ int main(int argc, char *argv[]) {
bool shs_cap_key_str_arg = false; bool shs_cap_key_str_arg = false;
bool ipv4_arg = false; bool ipv4_arg = false;
bool ipv6_arg = false; bool ipv6_arg = false;
bool passthrough = false;
enum ip_family ip_family; enum ip_family ip_family;
get_app_dir(app_dir, sizeof(app_dir)); get_app_dir(app_dir, sizeof(app_dir));
@ -920,10 +986,12 @@ int main(int argc, char *argv[]) {
case 'n': noauth = true; break; case 'n': noauth = true; break;
case '4': ipv4_arg = true; break; case '4': ipv4_arg = true; break;
case '6': ipv6_arg = true; break; case '6': ipv6_arg = true; break;
case 'a': passthrough = true; break;
default: usage(); default: usage();
} }
} }
if (i < argc) methodstr = argv[i++]; else if (!test) usage(); if (i < argc) methodstr = argv[i++];
else if (!test && !passthrough) usage();
if (ipv4_arg && ipv6_arg) errx(1, "options -4 and -6 conflict"); if (ipv4_arg && ipv6_arg) errx(1, "options -4 and -6 conflict");
ip_family = ip_family =
@ -941,9 +1009,15 @@ int main(int argc, char *argv[]) {
argument_len = test ? 0 : args_to_json_length(argc-i, argv+i); argument_len = test ? 0 : args_to_json_length(argc-i, argv+i);
char argument[argument_len]; char argument[argument_len];
if (!test) { if (passthrough) {
if (methodstr) errx(1, "-a option conflicts with method");
if (typestr) errx(1, "-a option conflicts with -t option");
if (argc-i > 0) errx(1, "-a option conflicts with method arguments");
if (test) errx(1, "-a option conflicts with -T test");
} else if (!test) {
rc = args_to_json(argument, sizeof(argument), argc-i, argv+i); rc = args_to_json(argument, sizeof(argument), argc-i, argv+i);
if (rc < 0) errx(0, "unable to collect arguments"); if (rc < 0) errx(1, "unable to collect arguments");
char manifest_buf[8192]; char manifest_buf[8192];
if (!typestr) { if (!typestr) {
@ -1040,6 +1114,12 @@ do_tcp_connect:
return 0; return 0;
} }
if (passthrough) {
rc = bs_passthrough(&bs, STDIN_FILENO, STDOUT_FILENO);
close(s);
return rc;
}
muxrpc_call(&bs, method, argument, type, typestr, 1); muxrpc_call(&bs, method, argument, type, typestr, 1);
switch (type) { switch (type) {

Loading…
Cancel
Save