|
|
@ -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) {
|
|
|
|