sbotc.cView |
---|
105 | 105 … | static void usage() { |
106 | 106 … | fputs("usage: sbotc [-j] [-T]\n" |
107 | 107 … | " [ -n | [-c <cap>] [-k <key>] [-K <keypair_seed>] ]\n" |
108 | 108 … | " [ [-s <host>] [-p <port>] [ -4 | -6 ] | [-u <socket_path>] ]\n" |
109 | | - " [-t <type>] <method> [<argument>...]\n", stderr); |
| 109 … | + " [ -a | [-t <type>] <method> [<argument>...] ]\n", stderr); |
110 | 110 … | exit(EXIT_FAILURE); |
111 | 111 … | } |
112 | 112 … | |
113 | 113 … | static int tcp_connect(const char *host, const char *port, enum ip_family ip_family) { |
175 | 175 … | } |
176 | 176 … | return 0; |
177 | 177 … | } |
178 | 178 … | |
| 179 … | +static int read_some(int fd, unsigned char *buf, size_t *lenp) { |
| 180 … | + ssize_t nbytes; |
| 181 … | + do nbytes = read(fd, buf, *lenp); |
| 182 … | + while (nbytes < 0 && errno == EINTR); |
| 183 … | + if (nbytes == 0) { errno = EPIPE; return -1; } |
| 184 … | + if (nbytes < 0) return -1; |
| 185 … | + *lenp = nbytes; |
| 186 … | + return 0; |
| 187 … | +} |
| 188 … | + |
179 | 189 … | static int write_all(int fd, const void *buf, size_t count) { |
180 | 190 … | ssize_t nbytes; |
181 | 191 … | while (count > 0) { |
182 | 192 … | nbytes = write(fd, buf, count); |
484 | 494 … | static void bs_end(struct boxs *bs) { |
485 | 495 … | if (!bs->noauth) { |
486 | 496 … | bs_write_end_box(bs); |
487 | 497 … | } |
| 498 … | + shutdown(bs->s, SHUT_WR); |
488 | 499 … | } |
489 | 500 … | |
490 | 501 … | static int bs_read_packet(struct boxs *bs, void *buf, size_t *lenp) { |
| 502 … | + int rc; |
| 503 … | + if (bs->noauth) { |
| 504 … | + rc = read_some(bs->s, buf, lenp); |
| 505 … | + if (rc < 0 && errno == EPIPE) return -1; |
| 506 … | + if (rc < 0) err(1, "failed to read packet data"); |
| 507 … | + return 0; |
| 508 … | + } |
491 | 509 … | unsigned char boxed_header[34]; |
492 | 510 … | struct boxs_header header; |
493 | | - int rc = read_all(bs->s, boxed_header, 34); |
| 511 … | + rc = read_all(bs->s, boxed_header, 34); |
494 | 512 … | if (rc < 0 && errno == EPIPE) errx(1, "unexpected end of parent stream"); |
495 | 513 … | if (rc < 0) err(1, "failed to read boxed packet header"); |
496 | 514 … | rc = crypto_secretbox_open_easy((unsigned char *)&header, boxed_header, 34, bs->rx_nonce, bs->decrypt_key); |
497 | 515 … | if (rc < 0) errx(1, "failed to unbox packet header"); |
530 | 548 … | } |
531 | 549 … | return 0; |
532 | 550 … | } |
533 | 551 … | |
| 552 … | +static enum stream_state bs_read_out_1(struct boxs *bs, int fd) { |
| 553 … | + size_t buf[4096]; |
| 554 … | + size_t len = sizeof(buf); |
| 555 … | + int rc; |
| 556 … | + rc = bs_read_packet(bs, buf, &len); |
| 557 … | + if (rc < 0 && errno == EPIPE) return stream_state_ended_ok; |
| 558 … | + if (rc < 0) return stream_state_ended_error; |
| 559 … | + rc = write_all(fd, buf, len); |
| 560 … | + if (rc < 0) return stream_state_ended_error; |
| 561 … | + return stream_state_open; |
| 562 … | +} |
| 563 … | + |
534 | 564 … | static int bs_read_out(struct boxs *bs, int fd, size_t len) { |
535 | 565 … | size_t chunk; |
536 | 566 … | char buf[4096]; |
537 | 567 … | int rc; |
577 | 607 … | buf += l; |
578 | 608 … | } |
579 | 609 … | } |
580 | 610 … | |
| 611 … | +static enum stream_state bs_write_in_1(struct boxs *bs, int fd) { |
| 612 … | + unsigned char buf[4096]; |
| 613 … | + ssize_t sz = read(fd, buf, sizeof(buf)); |
| 614 … | + if (sz < 0) err(1, "read"); |
| 615 … | + if (sz == 0) { |
| 616 … | + bs_end(bs); |
| 617 … | + return stream_state_ended_ok; |
| 618 … | + } |
| 619 … | + bs_write(bs, buf, sz); |
| 620 … | + return stream_state_open; |
| 621 … | +} |
| 622 … | + |
|
581 | 623 … | static void ps_write(struct boxs *bs, const char *data, size_t len, enum pkt_type type, int req_id, bool stream, bool end) { |
582 | 624 … | size_t out_len = 9 + len; |
583 | 625 … | unsigned char out_buf[out_len]; |
584 | 626 … | struct pkt_header header = {htonl(len), htonl(req_id)}; |
618 | 660 … | |
619 | 661 … | ps_write(bs, req, reqlen, pkt_type_json, req_id, !is_request, false); |
620 | 662 … | } |
621 | 663 … | |
| 664 … | +static int bs_passthrough(struct boxs *bs, int infd, int outfd) { |
| 665 … | + int rc; |
| 666 … | + fd_set rd; |
| 667 … | + int sfd = bs->s; |
| 668 … | + int maxfd = infd > sfd ? infd : sfd; |
| 669 … | + enum stream_state in = stream_state_open; |
| 670 … | + enum stream_state out = stream_state_open; |
| 671 … | + |
| 672 … | + while (out == stream_state_open |
| 673 … | + || (in == stream_state_open && out != stream_state_ended_error)) { |
| 674 … | + FD_ZERO(&rd); |
| 675 … | + if (in == stream_state_open) FD_SET(infd, &rd); |
| 676 … | + if (out == stream_state_open) FD_SET(sfd, &rd); |
| 677 … | + rc = select(maxfd + 1, &rd, 0, 0, NULL); |
| 678 … | + if (rc < 0) err(1, "select"); |
| 679 … | + if (FD_ISSET(infd, &rd)) in = bs_write_in_1(bs, infd); |
| 680 … | + if (FD_ISSET(sfd, &rd)) out = bs_read_out_1(bs, outfd); |
| 681 … | + } |
| 682 … | + |
| 683 … | + return in == stream_state_ended_ok && out == stream_state_ended_ok ? 0 : |
| 684 … | + in == stream_state_ended_error || out == stream_state_ended_error ? 2 : 1; |
| 685 … | +} |
| 686 … | + |
622 | 687 … | static void ps_reject(struct boxs *bs, size_t len, int32_t req, enum pkt_flags flags) { |
623 | 688 … | |
624 | 689 … | |
625 | 690 … | (void)req; |
865 | 930 … | const char *key = NULL; |
866 | 931 … | const char *keypair_seed_str = NULL; |
867 | 932 … | const char *host = NULL; |
868 | 933 … | const char *port = "8008"; |
869 | | - const char *typestr = NULL, *methodstr; |
| 934 … | + const char *typestr = NULL, *methodstr = NULL; |
870 | 935 … | const char *shs_cap_key_str = NULL; |
871 | 936 … | const char *socket_path = NULL; |
872 | 937 … | size_t argument_len; |
873 | 938 … | unsigned char private_key[64]; |
886 | 951 … | bool key_arg = false; |
887 | 952 … | bool shs_cap_key_str_arg = false; |
888 | 953 … | bool ipv4_arg = false; |
889 | 954 … | bool ipv6_arg = false; |
| 955 … | + bool passthrough = false; |
890 | 956 … | enum ip_family ip_family; |
891 | 957 … | |
892 | 958 … | get_app_dir(app_dir, sizeof(app_dir)); |
893 | 959 … | |
919 | 985 … | case 't': typestr = argv[++i]; break; |
920 | 986 … | case 'n': noauth = true; break; |
921 | 987 … | case '4': ipv4_arg = true; break; |
922 | 988 … | case '6': ipv6_arg = true; break; |
| 989 … | + case 'a': passthrough = true; break; |
923 | 990 … | default: usage(); |
924 | 991 … | } |
925 | 992 … | } |
926 | | - if (i < argc) methodstr = argv[i++]; else if (!test) usage(); |
| 993 … | + if (i < argc) methodstr = argv[i++]; |
| 994 … | + else if (!test && !passthrough) usage(); |
927 | 995 … | |
928 | 996 … | if (ipv4_arg && ipv6_arg) errx(1, "options -4 and -6 conflict"); |
929 | 997 … | ip_family = |
930 | 998 … | ipv4_arg ? ip_family_ipv4 : |
940 | 1008 … | |
941 | 1009 … | argument_len = test ? 0 : args_to_json_length(argc-i, argv+i); |
942 | 1010 … | char argument[argument_len]; |
943 | 1011 … | |
944 | | - if (!test) { |
| 1012 … | + if (passthrough) { |
| 1013 … | + if (methodstr) errx(1, "-a option conflicts with method"); |
| 1014 … | + if (typestr) errx(1, "-a option conflicts with -t option"); |
| 1015 … | + if (argc-i > 0) errx(1, "-a option conflicts with method arguments"); |
| 1016 … | + if (test) errx(1, "-a option conflicts with -T test"); |
| 1017 … | + |
| 1018 … | + } else if (!test) { |
945 | 1019 … | rc = args_to_json(argument, sizeof(argument), argc-i, argv+i); |
946 | | - if (rc < 0) errx(0, "unable to collect arguments"); |
| 1020 … | + if (rc < 0) errx(1, "unable to collect arguments"); |
947 | 1021 … | |
948 | 1022 … | char manifest_buf[8192]; |
949 | 1023 … | if (!typestr) { |
950 | 1024 … | len = read_file(manifest_buf, sizeof(manifest_buf), |
1039 | 1113 … | if (rc < 0) err(1, "failed to write handshake result"); |
1040 | 1114 … | return 0; |
1041 | 1115 … | } |
1042 | 1116 … | |
| 1117 … | + if (passthrough) { |
| 1118 … | + rc = bs_passthrough(&bs, STDIN_FILENO, STDOUT_FILENO); |
| 1119 … | + close(s); |
| 1120 … | + return rc; |
| 1121 … | + } |
| 1122 … | + |
1043 | 1123 … | muxrpc_call(&bs, method, argument, type, typestr, 1); |
1044 | 1124 … | |
1045 | 1125 … | switch (type) { |
1046 | 1126 … | case muxrpc_type_async: |