sbotc.cView |
---|
86 | 86 … | stream_state_ended_ok, |
87 | 87 … | stream_state_ended_error, |
88 | 88 … | }; |
89 | 89 … | |
| 90 … | +enum ip_family { |
| 91 … | + ip_family_ipv4 = AF_INET, |
| 92 … | + ip_family_ipv6 = AF_INET6, |
| 93 … | + ip_family_any = AF_UNSPEC |
| 94 … | +}; |
| 95 … | + |
90 | 96 … | static unsigned char zeros[24] = {0}; |
91 | 97 … | |
92 | 98 … | static const unsigned char ssb_cap[] = { |
93 | 99 … | 0xd4, 0xa1, 0xcb, 0x88, 0xa6, 0x6f, 0x02, 0xf8, |
98 | 104 … | |
99 | 105 … | static void usage() { |
100 | 106 … | fputs("usage: sbotc [-j] [-T]\n" |
101 | 107 … | " [ -n | [-c <cap>] [-k <key>] [-K <keypair_seed>] ]\n" |
102 | | - " [ [-s <host>] [-p <port>] | [-u <socket_path>] ]\n" |
| 108 … | + " [ [-s <host>] [-p <port>] [ -4 | -6 ] | [-u <socket_path>] ]\n" |
103 | 109 … | " [-t <type>] <method> [<argument>...]\n", stderr); |
104 | 110 … | exit(EXIT_FAILURE); |
105 | 111 … | } |
106 | 112 … | |
107 | | -static int tcp_connect(const char *host, const char *port) { |
| 113 … | +static int tcp_connect(const char *host, const char *port, enum ip_family ip_family) { |
108 | 114 … | struct addrinfo hints; |
109 | 115 … | struct addrinfo *result, *rp; |
110 | 116 … | int s; |
111 | 117 … | int fd; |
112 | 118 … | int err; |
113 | 119 … | |
114 | 120 … | memset(&hints, 0, sizeof(hints)); |
115 | | - hints.ai_family = AF_UNSPEC; |
| 121 … | + hints.ai_family = ip_family; |
116 | 122 … | hints.ai_protocol = IPPROTO_TCP; |
117 | 123 … | |
118 | 124 … | s = getaddrinfo(host, port, &hints, &result); |
119 | 125 … | if (s < 0) errx(1, "unable to resolve host: %s", gai_strerror(s)); |
862 | 868 … | bool host_arg = false; |
863 | 869 … | bool port_arg = false; |
864 | 870 … | bool key_arg = false; |
865 | 871 … | bool shs_cap_key_str_arg = false; |
| 872 … | + bool ipv4_arg = false; |
| 873 … | + bool ipv6_arg = false; |
| 874 … | + enum ip_family ip_family; |
866 | 875 … | |
867 | 876 … | get_app_dir(app_dir, sizeof(app_dir)); |
868 | 877 … | |
869 | 878 … | char config_buf[8192]; |
892 | 901 … | case 'p': port = argv[++i]; port_arg = true; break; |
893 | 902 … | case 'u': socket_path = argv[++i]; break; |
894 | 903 … | case 't': typestr = argv[++i]; break; |
895 | 904 … | case 'n': noauth = true; break; |
| 905 … | + case '4': ipv4_arg = true; break; |
| 906 … | + case '6': ipv6_arg = true; break; |
896 | 907 … | default: usage(); |
897 | 908 … | } |
898 | 909 … | } |
899 | 910 … | if (i < argc) methodstr = argv[i++]; else if (!test) usage(); |
900 | 911 … | |
| 912 … | + if (ipv4_arg && ipv6_arg) errx(1, "options -4 and -6 conflict"); |
| 913 … | + ip_family = |
| 914 … | + ipv4_arg ? ip_family_ipv4 : |
| 915 … | + ipv6_arg ? ip_family_ipv6 : |
| 916 … | + ip_family_any; |
| 917 … | + |
901 | 918 … | if (shs_cap_key_str) { |
902 | 919 … | rc = pubkey_decode(shs_cap_key_str, shs_cap_key); |
903 | 920 … | if (rc < 0) err(1, "unable to decode cap key '%s'", shs_cap_key_str); |
904 | 921 … | } else { |
956 | 973 … | } else { |
957 | 974 … | memcpy(remote_key, public_key, 32); |
958 | 975 … | } |
959 | 976 … | |
960 | | - bool implied_tcp = host_arg || port_arg; |
| 977 … | + bool implied_tcp = host_arg || port_arg || ipv4_arg || ipv6_arg; |
961 | 978 … | bool implied_auth = key_arg || keypair_seed_str || shs_cap_key_str_arg || test; |
962 | 979 … | |
963 | 980 … | if (test) { |
964 | 981 … | infd = STDIN_FILENO; |
983 | 1000 … | infd = outfd = s; |
984 | 1001 … | |
985 | 1002 … | } else { |
986 | 1003 … | do_tcp_connect: |
987 | | - s = tcp_connect(host, port); |
| 1004 … | + s = tcp_connect(host, port, ip_family); |
988 | 1005 … | if (s < 0) err(1, "tcp_connect"); |
989 | 1006 … | infd = outfd = s; |
990 | 1007 … | } |
991 | 1008 … | |