main: Add option to disable SR advertisement
[nbdkit/ericb.git] / server / protocol-handshake-newstyle.c
blob6ccb76f3fa08b581fe34c916e7f30714719835c5
1 /* nbdkit
2 * Copyright (C) 2013-2019 Red Hat Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <inttypes.h>
39 #include <string.h>
40 #include <unistd.h>
42 #include "internal.h"
43 #include "byte-swapping.h"
44 #include "protocol.h"
46 /* Maximum number of client options we allow before giving up. */
47 #define MAX_NR_OPTIONS 32
49 /* Maximum length of any option data (bytes). */
50 #define MAX_OPTION_LENGTH 4096
52 /* Receive newstyle options. */
53 static int
54 send_newstyle_option_reply (struct connection *conn,
55 uint32_t option, uint32_t reply)
57 struct fixed_new_option_reply fixed_new_option_reply;
59 fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
60 fixed_new_option_reply.option = htobe32 (option);
61 fixed_new_option_reply.reply = htobe32 (reply);
62 fixed_new_option_reply.replylen = htobe32 (0);
64 if (conn->send (conn,
65 &fixed_new_option_reply,
66 sizeof fixed_new_option_reply, 0) == -1) {
67 /* The protocol document says that the client is allowed to simply
68 * drop the connection after sending NBD_OPT_ABORT, or may read
69 * the reply.
71 if (option == NBD_OPT_ABORT)
72 debug ("write: %s: %m", name_of_nbd_opt (option));
73 else
74 nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
75 return -1;
78 return 0;
81 static int
82 send_newstyle_option_reply_exportname (struct connection *conn,
83 uint32_t option, uint32_t reply,
84 const char *exportname)
86 struct fixed_new_option_reply fixed_new_option_reply;
87 size_t name_len = strlen (exportname);
88 uint32_t len;
90 fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
91 fixed_new_option_reply.option = htobe32 (option);
92 fixed_new_option_reply.reply = htobe32 (reply);
93 fixed_new_option_reply.replylen = htobe32 (name_len + sizeof (len));
95 if (conn->send (conn,
96 &fixed_new_option_reply,
97 sizeof fixed_new_option_reply, SEND_MORE) == -1) {
98 nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
99 return -1;
102 len = htobe32 (name_len);
103 if (conn->send (conn, &len, sizeof len, SEND_MORE) == -1) {
104 nbdkit_error ("write: %s: %s: %m",
105 name_of_nbd_opt (option), "sending length");
106 return -1;
108 if (conn->send (conn, exportname, name_len, 0) == -1) {
109 nbdkit_error ("write: %s: %s: %m",
110 name_of_nbd_opt (option), "sending export name");
111 return -1;
114 return 0;
117 static int
118 send_newstyle_option_reply_info_export (struct connection *conn,
119 uint32_t option, uint32_t reply,
120 uint16_t info)
122 struct fixed_new_option_reply fixed_new_option_reply;
123 struct fixed_new_option_reply_info_export export;
125 fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
126 fixed_new_option_reply.option = htobe32 (option);
127 fixed_new_option_reply.reply = htobe32 (reply);
128 fixed_new_option_reply.replylen = htobe32 (sizeof export);
129 export.info = htobe16 (info);
130 export.exportsize = htobe64 (conn->exportsize);
131 export.eflags = htobe16 (conn->eflags);
133 if (conn->send (conn,
134 &fixed_new_option_reply,
135 sizeof fixed_new_option_reply, SEND_MORE) == -1 ||
136 conn->send (conn, &export, sizeof export, 0) == -1) {
137 nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
138 return -1;
141 return 0;
144 static int
145 send_newstyle_option_reply_meta_context (struct connection *conn,
146 uint32_t option, uint32_t reply,
147 uint32_t context_id,
148 const char *name)
150 struct fixed_new_option_reply fixed_new_option_reply;
151 struct fixed_new_option_reply_meta_context context;
152 const size_t namelen = strlen (name);
154 debug ("newstyle negotiation: %s: replying with %s id %d",
155 name_of_nbd_opt (option), name, context_id);
156 fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
157 fixed_new_option_reply.option = htobe32 (option);
158 fixed_new_option_reply.reply = htobe32 (reply);
159 fixed_new_option_reply.replylen = htobe32 (sizeof context + namelen);
160 context.context_id = htobe32 (context_id);
162 if (conn->send (conn,
163 &fixed_new_option_reply,
164 sizeof fixed_new_option_reply, SEND_MORE) == -1 ||
165 conn->send (conn, &context, sizeof context, SEND_MORE) == -1 ||
166 conn->send (conn, name, namelen, 0) == -1) {
167 nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
168 return -1;
171 return 0;
174 /* Sub-function during negotiate_handshake_newstyle, to uniformly handle
175 * a client hanging up on a message boundary.
177 static int __attribute__ ((format (printf, 4, 5)))
178 conn_recv_full (struct connection *conn, void *buf, size_t len,
179 const char *fmt, ...)
181 int r = conn->recv (conn, buf, len);
182 va_list args;
184 if (r == -1) {
185 va_start (args, fmt);
186 nbdkit_verror (fmt, args);
187 va_end (args);
188 return -1;
190 if (r == 0) {
191 /* During negotiation, client EOF on message boundary is less
192 * severe than failure in the middle of the buffer. */
193 debug ("client closed input socket, closing connection");
194 return -1;
196 return r;
199 /* Sub-function of negotiate_handshake_newstyle_options below. It
200 * must be called on all non-error paths out of the options for-loop
201 * in that function.
203 static int
204 finish_newstyle_options (struct connection *conn)
206 int64_t r;
208 r = backend->get_size (backend, conn);
209 if (r == -1)
210 return -1;
211 if (r < 0) {
212 nbdkit_error (".get_size function returned invalid value "
213 "(%" PRIi64 ")", r);
214 return -1;
216 conn->exportsize = (uint64_t) r;
218 if (protocol_compute_eflags (conn, &conn->eflags) < 0)
219 return -1;
221 debug ("newstyle negotiation: flags: export 0x%x", conn->eflags);
222 return 0;
225 static int
226 negotiate_handshake_newstyle_options (struct connection *conn)
228 struct new_option new_option;
229 size_t nr_options;
230 uint64_t version;
231 uint32_t option;
232 uint32_t optlen;
233 char data[MAX_OPTION_LENGTH+1];
234 struct new_handshake_finish handshake_finish;
235 const char *optname;
237 for (nr_options = 0; nr_options < MAX_NR_OPTIONS; ++nr_options) {
238 if (conn_recv_full (conn, &new_option, sizeof new_option,
239 "reading option: conn->recv: %m") == -1)
240 return -1;
242 version = be64toh (new_option.version);
243 if (version != NEW_VERSION) {
244 nbdkit_error ("unknown option version %" PRIx64
245 ", expecting %" PRIx64,
246 version, NEW_VERSION);
247 return -1;
250 /* There is a maximum option length we will accept, regardless
251 * of the option type.
253 optlen = be32toh (new_option.optlen);
254 if (optlen > MAX_OPTION_LENGTH) {
255 nbdkit_error ("client option data too long (%" PRIu32 ")", optlen);
256 return -1;
259 option = be32toh (new_option.option);
260 optname = name_of_nbd_opt (option);
262 /* In --tls=require / FORCEDTLS mode the only options allowed
263 * before TLS negotiation are NBD_OPT_ABORT and NBD_OPT_STARTTLS.
265 if (tls == 2 && !conn->using_tls &&
266 !(option == NBD_OPT_ABORT || option == NBD_OPT_STARTTLS)) {
267 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_TLS_REQD))
268 return -1;
269 continue;
272 switch (option) {
273 case NBD_OPT_EXPORT_NAME:
274 if (conn_recv_full (conn, data, optlen,
275 "read: %s: %m", name_of_nbd_opt (option)) == -1)
276 return -1;
277 /* Apart from printing it, ignore the export name. */
278 data[optlen] = '\0';
279 debug ("newstyle negotiation: %s: "
280 "client requested export '%s' (ignored)",
281 name_of_nbd_opt (option), data);
283 /* We have to finish the handshake by sending handshake_finish. */
284 if (finish_newstyle_options (conn) == -1)
285 return -1;
287 memset (&handshake_finish, 0, sizeof handshake_finish);
288 handshake_finish.exportsize = htobe64 (conn->exportsize);
289 handshake_finish.eflags = htobe16 (conn->eflags);
291 if (conn->send (conn,
292 &handshake_finish,
293 (conn->cflags & NBD_FLAG_NO_ZEROES)
294 ? offsetof (struct new_handshake_finish, zeroes)
295 : sizeof handshake_finish, 0) == -1) {
296 nbdkit_error ("write: %s: %m", optname);
297 return -1;
299 break;
301 case NBD_OPT_ABORT:
302 if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
303 return -1;
304 debug ("client sent %s to abort the connection",
305 name_of_nbd_opt (option));
306 return -1;
308 case NBD_OPT_LIST:
309 if (optlen != 0) {
310 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
311 == -1)
312 return -1;
313 if (conn_recv_full (conn, data, optlen,
314 "read: %s: %m", name_of_nbd_opt (option)) == -1)
315 return -1;
316 continue;
319 /* Send back the exportname. */
320 debug ("newstyle negotiation: %s: advertising export '%s'",
321 name_of_nbd_opt (option), exportname);
322 if (send_newstyle_option_reply_exportname (conn, option, NBD_REP_SERVER,
323 exportname) == -1)
324 return -1;
326 if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
327 return -1;
328 break;
330 case NBD_OPT_STARTTLS:
331 if (optlen != 0) {
332 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
333 == -1)
334 return -1;
335 if (conn_recv_full (conn, data, optlen,
336 "read: %s: %m", name_of_nbd_opt (option)) == -1)
337 return -1;
338 continue;
341 if (tls == 0) { /* --tls=off (NOTLS mode). */
342 #ifdef HAVE_GNUTLS
343 #define NO_TLS_REPLY NBD_REP_ERR_POLICY
344 #else
345 #define NO_TLS_REPLY NBD_REP_ERR_UNSUP
346 #endif
347 if (send_newstyle_option_reply (conn, option, NO_TLS_REPLY) == -1)
348 return -1;
350 else /* --tls=on or --tls=require */ {
351 /* We can't upgrade to TLS twice on the same connection. */
352 if (conn->using_tls) {
353 if (send_newstyle_option_reply (conn, option,
354 NBD_REP_ERR_INVALID) == -1)
355 return -1;
356 continue;
359 /* We have to send the (unencrypted) reply before starting
360 * the handshake.
362 if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
363 return -1;
365 /* Upgrade the connection to TLS. Also performs access control. */
366 if (crypto_negotiate_tls (conn, conn->sockin, conn->sockout) == -1)
367 return -1;
368 conn->using_tls = true;
369 debug ("using TLS on this connection");
371 break;
373 case NBD_OPT_INFO:
374 case NBD_OPT_GO:
375 if (conn_recv_full (conn, data, optlen,
376 "read: %s: %m", optname) == -1)
377 return -1;
379 if (optlen < 6) { /* 32 bit export length + 16 bit nr info */
380 debug ("newstyle negotiation: %s option length < 6", optname);
382 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
383 == -1)
384 return -1;
385 continue;
389 uint32_t exportnamelen;
390 uint16_t nrinfos;
391 uint16_t info;
392 size_t i;
393 CLEANUP_FREE char *requested_exportname = NULL;
395 /* Validate the name length and number of INFO requests. */
396 memcpy (&exportnamelen, &data[0], 4);
397 exportnamelen = be32toh (exportnamelen);
398 if (exportnamelen > optlen-6 /* NB optlen >= 6, see above */) {
399 debug ("newstyle negotiation: %s: export name too long", optname);
400 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
401 == -1)
402 return -1;
403 continue;
405 memcpy (&nrinfos, &data[exportnamelen+4], 2);
406 nrinfos = be16toh (nrinfos);
407 if (optlen != 4 + exportnamelen + 2 + 2*nrinfos) {
408 debug ("newstyle negotiation: %s: "
409 "number of information requests incorrect", optname);
410 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
411 == -1)
412 return -1;
413 continue;
416 /* As with NBD_OPT_EXPORT_NAME we print the export name and then
417 * ignore it.
419 requested_exportname = malloc (exportnamelen+1);
420 if (requested_exportname == NULL) {
421 nbdkit_error ("malloc: %m");
422 return -1;
424 memcpy (requested_exportname, &data[4], exportnamelen);
425 requested_exportname[exportnamelen] = '\0';
426 debug ("newstyle negotiation: %s: "
427 "client requested export '%s' (ignored)",
428 optname, requested_exportname);
430 /* The spec is confusing, but it is required that we send back
431 * NBD_INFO_EXPORT, even if the client did not request it!
432 * qemu client in particular does not request this, but will
433 * fail if we don't send it.
435 if (finish_newstyle_options (conn) == -1)
436 return -1;
438 if (send_newstyle_option_reply_info_export (conn, option,
439 NBD_REP_INFO,
440 NBD_INFO_EXPORT) == -1)
441 return -1;
443 /* For now we ignore all other info requests (but we must
444 * ignore NBD_INFO_EXPORT if it was requested, because we
445 * replied already above). Therefore this loop doesn't do
446 * much at the moment.
448 for (i = 0; i < nrinfos; ++i) {
449 memcpy (&info, &data[4 + exportnamelen + 2 + i*2], 2);
450 info = be16toh (info);
451 switch (info) {
452 case NBD_INFO_EXPORT: /* ignore - reply sent above */ break;
453 default:
454 debug ("newstyle negotiation: %s: "
455 "ignoring NBD_INFO_* request %u (%s)",
456 optname, (unsigned) info, name_of_nbd_info (info));
457 break;
462 /* Unlike NBD_OPT_EXPORT_NAME, NBD_OPT_GO sends back an ACK
463 * or ERROR packet.
465 if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
466 return -1;
468 break;
470 case NBD_OPT_STRUCTURED_REPLY:
471 if (optlen != 0) {
472 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
473 == -1)
474 return -1;
475 if (conn_recv_full (conn, data, optlen,
476 "read: %s: %m", name_of_nbd_opt (option)) == -1)
477 return -1;
478 continue;
481 debug ("newstyle negotiation: %s: client requested structured replies",
482 name_of_nbd_opt (option));
484 if (no_sr) {
485 /* Must fail with ERR_UNSUP for qemu 4.2 to remain happy;
486 * but failing with ERR_POLICY would have been nicer.
488 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_UNSUP) == -1)
489 return -1;
490 debug ("newstyle negotiation: %s: structured replies are disabled",
491 name_of_nbd_opt (option));
492 break;
495 if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
496 return -1;
498 conn->structured_replies = true;
499 break;
501 case NBD_OPT_LIST_META_CONTEXT:
502 case NBD_OPT_SET_META_CONTEXT:
504 uint32_t opt_index;
505 uint32_t exportnamelen;
506 uint32_t nr_queries;
507 uint32_t querylen;
508 const char *what;
510 if (conn_recv_full (conn, data, optlen, "read: %s: %m", optname) == -1)
511 return -1;
513 /* Note that we support base:allocation whether or not the plugin
514 * supports can_extents.
516 if (!conn->structured_replies) {
517 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
518 == -1)
519 return -1;
520 continue;
523 /* Minimum length of the option payload is:
524 * 32 bit export name length followed by empty export name
525 * + 32 bit number of queries followed by no queries
526 * = 8 bytes.
528 what = "optlen < 8";
529 if (optlen < 8) {
530 opt_meta_invalid_option_len:
531 debug ("newstyle negotiation: %s: invalid option length: %s",
532 optname, what);
534 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
535 == -1)
536 return -1;
537 continue;
540 /* Discard the export name. */
541 memcpy (&exportnamelen, &data[0], 4);
542 exportnamelen = be32toh (exportnamelen);
543 opt_index = 4 + exportnamelen;
545 /* Read the number of queries. */
546 what = "reading number of queries";
547 if (opt_index+4 > optlen)
548 goto opt_meta_invalid_option_len;
549 memcpy (&nr_queries, &data[opt_index], 4);
550 nr_queries = be32toh (nr_queries);
551 opt_index += 4;
553 /* for LIST: nr_queries == 0 means return all meta contexts
554 * for SET: nr_queries == 0 means reset all contexts
556 debug ("newstyle negotiation: %s: %s count: %d", optname,
557 option == NBD_OPT_LIST_META_CONTEXT ? "query" : "set",
558 nr_queries);
559 if (nr_queries == 0) {
560 if (option == NBD_OPT_SET_META_CONTEXT)
561 conn->meta_context_base_allocation = false;
562 else /* LIST */ {
563 if (send_newstyle_option_reply_meta_context
564 (conn, option, NBD_REP_META_CONTEXT,
565 0, "base:allocation") == -1)
566 return -1;
569 if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
570 return -1;
572 else {
573 /* Read and answer each query. */
574 while (nr_queries > 0) {
575 what = "reading query string length";
576 if (opt_index+4 > optlen)
577 goto opt_meta_invalid_option_len;
578 memcpy (&querylen, &data[opt_index], 4);
579 querylen = be32toh (querylen);
580 opt_index += 4;
581 what = "reading query string";
582 if (opt_index + querylen > optlen)
583 goto opt_meta_invalid_option_len;
585 debug ("newstyle negotiation: %s: %s %.*s",
586 optname,
587 option == NBD_OPT_LIST_META_CONTEXT ? "query" : "set",
588 (int) querylen, &data[opt_index]);
590 /* For LIST, "base:" returns all supported contexts in the
591 * base namespace. We only support "base:allocation".
593 if (option == NBD_OPT_LIST_META_CONTEXT &&
594 querylen == 5 &&
595 strncmp (&data[opt_index], "base:", 5) == 0) {
596 if (send_newstyle_option_reply_meta_context
597 (conn, option, NBD_REP_META_CONTEXT,
598 0, "base:allocation") == -1)
599 return -1;
601 /* "base:allocation" requested by name. */
602 else if (querylen == 15 &&
603 strncmp (&data[opt_index], "base:allocation", 15) == 0) {
604 if (send_newstyle_option_reply_meta_context
605 (conn, option, NBD_REP_META_CONTEXT,
606 option == NBD_OPT_SET_META_CONTEXT
607 ? base_allocation_id : 0,
608 "base:allocation") == -1)
609 return -1;
610 if (option == NBD_OPT_SET_META_CONTEXT)
611 conn->meta_context_base_allocation = true;
613 /* Every other query must be ignored. */
615 opt_index += querylen;
616 nr_queries--;
618 if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
619 return -1;
621 debug ("newstyle negotiation: %s: reply complete", optname);
623 break;
625 default:
626 /* Unknown option. */
627 if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_UNSUP) == -1)
628 return -1;
629 if (conn_recv_full (conn, data, optlen,
630 "reading unknown option data: conn->recv: %m") == -1)
631 return -1;
634 /* Note, since it's not very clear from the protocol doc, that the
635 * client must send NBD_OPT_EXPORT_NAME or NBD_OPT_GO last, and
636 * that ends option negotiation.
638 if (option == NBD_OPT_EXPORT_NAME || option == NBD_OPT_GO)
639 break;
642 if (nr_options >= MAX_NR_OPTIONS) {
643 nbdkit_error ("client exceeded maximum number of options (%d)",
644 MAX_NR_OPTIONS);
645 return -1;
648 /* In --tls=require / FORCEDTLS mode, we must have upgraded to TLS
649 * by the time we finish option negotiation. If not, give up.
651 if (tls == 2 && !conn->using_tls) {
652 nbdkit_error ("non-TLS client tried to connect in --tls=require mode");
653 return -1;
656 return 0;
660 protocol_handshake_newstyle (struct connection *conn)
662 struct new_handshake handshake;
663 uint16_t gflags;
665 gflags = NBD_FLAG_FIXED_NEWSTYLE | NBD_FLAG_NO_ZEROES;
667 debug ("newstyle negotiation: flags: global 0x%x", gflags);
669 memcpy (handshake.nbdmagic, "NBDMAGIC", 8);
670 handshake.version = htobe64 (NEW_VERSION);
671 handshake.gflags = htobe16 (gflags);
673 if (conn->send (conn, &handshake, sizeof handshake, 0) == -1) {
674 nbdkit_error ("write: %s: %m", "sending newstyle handshake");
675 return -1;
678 /* Client now sends us its 32 bit flags word ... */
679 if (conn_recv_full (conn, &conn->cflags, sizeof conn->cflags,
680 "reading initial client flags: conn->recv: %m") == -1)
681 return -1;
682 conn->cflags = be32toh (conn->cflags);
683 /* ... which we check for accuracy. */
684 debug ("newstyle negotiation: client flags: 0x%x", conn->cflags);
685 if (conn->cflags & ~gflags) {
686 nbdkit_error ("client requested unknown flags 0x%x", conn->cflags);
687 return -1;
690 /* Receive newstyle options. */
691 if (negotiate_handshake_newstyle_options (conn) == -1)
692 return -1;
694 return 0;