2 * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
20 #include <sys/socket.h>
52 struct tls_config *tlsconf;
55 static void ATTR_DEAD usage(int);
57 static void sig_handler(int, short, void *);
59 static int openconn(void);
61 static void tls_readcb(int, short, void *);
62 static void tls_writecb(int, short, void *);
64 static void client_read(struct bufferevent *, void *);
65 static void client_write(struct bufferevent *, void *);
66 static void client_error(struct bufferevent *, short, void *);
68 static void readcmd(int, short, void *);
70 static void handle_9p(const void *, size_t);
71 static void prompt(void);
77 "usage: %s [-chv] [-C crt] [-K key] [-H host] [-P port]\n",
79 fprintf(stderr, PACKAGE_NAME " suite version " PACKAGE_VERSION "\n");
84 sig_handler(int sig, short event, void *d)
87 * Normal signal handler rules don't apply because libevent
94 log_warnx("\rShutting down...");
98 fatalx("unexpected signal %d", sig);
105 struct addrinfo hints, *res, *res0;
109 const char *cause = NULL;
111 memset(&hints, 0, sizeof(hints));
112 hints.ai_family = AF_UNSPEC;
113 hints.ai_socktype = SOCK_STREAM;
114 if ((error = getaddrinfo(host, port, &hints, &res0))) {
115 warnx("%s", gai_strerror(error));
120 for (res = res0; res; res = res->ai_next) {
121 s = socket(res->ai_family, res->ai_socktype,
128 if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
149 tls_readcb(int fd, short event, void *d)
151 struct bufferevent *bufev = d;
152 char buf[IBUF_READ_SIZE];
153 int what = EVBUFFER_READ;
154 int howmuch = IBUF_READ_SIZE;
158 if (event == EV_TIMEOUT) {
159 what |= EVBUFFER_TIMEOUT;
163 if (bufev->wm_read.high != 0)
164 howmuch = MIN(sizeof(buf), bufev->wm_read.high);
166 switch (ret = tls_read(ctx, buf, howmuch)) {
167 case TLS_WANT_POLLIN:
168 case TLS_WANT_POLLOUT:
171 what |= EVBUFFER_ERROR;
177 what |= EVBUFFER_EOF;
181 if (evbuffer_add(bufev->input, buf, len) == -1) {
182 what |= EVBUFFER_ERROR;
186 event_add(&bufev->ev_read, NULL);
188 len = EVBUFFER_LENGTH(bufev->input);
189 if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
191 if (bufev->readcb != NULL)
192 (*bufev->readcb)(bufev, bufev->cbarg);
196 event_add(&bufev->ev_read, NULL);
200 (*bufev->errorcb)(bufev, what, bufev->cbarg);
204 tls_writecb(int fd, short event, void *d)
206 struct bufferevent *bufev = d;
208 short what = EVBUFFER_WRITE;
210 if (event == EV_TIMEOUT) {
211 what |= EVBUFFER_TIMEOUT;
215 if (EVBUFFER_LENGTH(bufev->output) != 0) {
217 EVBUFFER_DATA(bufev->output),
218 EVBUFFER_LENGTH(bufev->output));
220 case TLS_WANT_POLLIN:
221 case TLS_WANT_POLLOUT:
224 what |= EVBUFFER_ERROR;
227 evbuffer_drain(bufev->output, ret);
230 if (EVBUFFER_LENGTH(bufev->output) != 0)
231 event_add(&bufev->ev_write, NULL);
233 if (bufev->writecb != NULL &&
234 EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
235 (*bufev->writecb)(bufev, bufev->cbarg);
239 event_add(&bufev->ev_write, NULL);
242 (*bufev->errorcb)(bufev, what, bufev->cbarg);
246 client_read(struct bufferevent *bev, void *data)
248 struct evbuffer *src = EVBUFFER_INPUT(bev);
252 if (EVBUFFER_LENGTH(src) < 4)
255 memcpy(&len, EVBUFFER_DATA(src), sizeof(len));
258 if (len > EVBUFFER_LENGTH(src))
261 handle_9p(EVBUFFER_DATA(src), len);
262 evbuffer_drain(src, len);
267 client_write(struct bufferevent *bev, void *data)
269 return; /* nothing to do */
273 client_error(struct bufferevent *bev, short err, void *data)
275 if (err & EVBUFFER_ERROR)
276 fatal("buffer event error");
278 if (err & EVBUFFER_EOF) {
286 log_warnx("unknown event error");
291 readcmd(int fd, short event, void *data)
297 if ((linelen = getline(&line, &linesize, stdin)) != -1) {
298 line[linelen-1] = '\0';
301 log_info("TODO: parse `%s'", line);
311 handle_9p(const void *data, size_t len)
313 struct np_msg_header hdr;
315 assert(len >= sizeof(hdr));
316 memcpy(&hdr, data, sizeof(hdr));
318 hdr.len = le32toh(hdr.len);
319 /* type is one byte long, no endianness issues */
320 hdr.tag = le16toh(hdr.tag);
323 log_info("[%d] type=%s len=%"PRIu32, hdr.tag, pp_msg_type(hdr.type),
331 printf("%s", PROMPT);
336 main(int argc, char **argv)
338 int ch, sock, handshake;
339 struct bufferevent *bev;
340 struct event inev, ev_sigint, ev_sigterm;
342 signal(SIGPIPE, SIG_IGN);
344 while ((ch = getopt(argc, argv, "C:cH:hK:P:v")) != -1) {
382 /* if (!tls || (crtpath != NULL || keypath != NULL)) */
385 errx(1, "must enable tls (for now)");
387 log_init(1, LOG_DAEMON);
388 log_setverbose(verbose);
389 log_procinit(getprogname());
391 if ((tlsconf = tls_config_new()) == NULL)
392 fatalx("tls_config_new");
393 tls_config_insecure_noverifycert(tlsconf);
394 tls_config_insecure_noverifyname(tlsconf);
395 if (tls_config_set_keypair_file(tlsconf, crtpath, keypath) == -1)
396 fatalx("can't load certs (%s, %s)", crtpath, keypath);
398 if ((ctx = tls_client()) == NULL)
400 if (tls_configure(ctx, tlsconf) == -1)
401 fatalx("tls_configure: %s", tls_error(ctx));
403 log_info("connecting to %s:%s...", host, port);
405 if ((sock = openconn()) == -1)
406 fatalx("can't connect to %s:%s", host, port);
408 if (tls_connect_socket(ctx, sock, host) == -1)
409 fatalx("tls_connect_socket: %s", tls_error(ctx));
411 for (handshake = 0; !handshake;) {
412 switch (tls_handshake(ctx)) {
414 fatalx("tls_handshake: %s", tls_error(ctx));
421 log_info("connected!");
425 signal_set(&ev_sigint, SIGINT, sig_handler, NULL);
426 signal_set(&ev_sigterm, SIGINT, sig_handler, NULL);
428 signal_add(&ev_sigint, NULL);
429 signal_add(&ev_sigterm, NULL);
431 bev = bufferevent_new(sock, client_read, client_write, client_error,
434 fatal("bufferevent_new");
437 event_set(&bev->ev_read, sock, EV_READ, tls_readcb, bev);
438 event_set(&bev->ev_write, sock, EV_WRITE, tls_writecb, bev);
440 bufferevent_setwatermark(bev, EV_READ|EV_WRITE,
441 sizeof(struct np_msg_header), 0);
442 bufferevent_enable(bev, EV_READ|EV_WRITE);
444 event_set(&inev, 0, EV_READ, readcmd, NULL);
445 event_add(&inev, NULL);
450 bufferevent_free(bev);
452 tls_config_free(tlsconf);