1 // SPDX-License-Identifier: GPL-2.0
2
3 /*
4 * Open connection for network block device
5 *
6 * Copyright 1997,1998 Pavel Machek, distribute under GPL
7 * <[email protected]>
8 * Copyright (c) 2002 - 2011 Wouter Verhelst <[email protected]>
9 *
10 * Version 1.0 - 64bit issues should be fixed, now
11 * Version 1.1 - added bs (blocksize) option (Alexey Guzeev, [email protected])
12 * Version 1.2 - I added new option '-d' to send the disconnect request
13 * Version 2.0 - Version synchronised with server
14 * Version 2.1 - Check for disconnection before INIT_PASSWD is received
15 * to make errormsg a bit more helpful in case the server can't
16 * open the exported file.
17 * 16/03/2010 - Add IPv6 support.
18 * Kitt Tientanopajai <[email protected]>
19 * Neutron Soutmun <[email protected]>
20 * Suriya Soutmun <[email protected]>
21 */
22
23 #include <config.h>
24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <netinet/tcp.h>
30 #include <netinet/in.h>
31 #include <netdb.h>
32 #include <inttypes.h>
33 #include <stdio.h>
34 #include <fcntl.h>
35 #include <syslog.h>
36 #include <stdlib.h>
37 #include <sys/mount.h>
38 #include <sys/mman.h>
39 #include <signal.h>
40 #include <errno.h>
41 #include <getopt.h>
42 #include <stdarg.h>
43 #include <stdbool.h>
44 #include <time.h>
45
46 #include <linux/ioctl.h>
47
48 #define MY_NAME "ublk_nbd"
49 #include "cliserv.h"
50
51 #if HAVE_GNUTLS && !defined(NOTLS)
52 #include "crypto-gnutls.h"
53 #endif
54
55 #define NBDC_DO_LIST 1
56
opennet(const char * name,const char * portstr,int sdp)57 int opennet(const char *name, const char* portstr, int sdp) {
58 int sock;
59 struct addrinfo hints;
60 struct addrinfo *ai = NULL;
61 struct addrinfo *rp = NULL;
62 int e;
63
64 memset(&hints,'\0',sizeof(hints));
65 hints.ai_family = AF_UNSPEC;
66 hints.ai_socktype = SOCK_STREAM;
67 hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
68 hints.ai_protocol = IPPROTO_TCP;
69
70 e = getaddrinfo(name, portstr, &hints, &ai);
71
72 if(e != 0) {
73 fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(e));
74 freeaddrinfo(ai);
75 return -1;
76 }
77
78 if(sdp) {
79 #ifdef WITH_SDP
80 if (ai->ai_family == AF_INET)
81 ai->ai_family = AF_INET_SDP;
82 else (ai->ai_family == AF_INET6)
83 ai->ai_family = AF_INET6_SDP;
84 #else
85 err("Can't do SDP: I was not compiled with SDP support!");
86 #endif
87 }
88
89 for(rp = ai; rp != NULL; rp = rp->ai_next) {
90 sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
91
92 if(sock == -1)
93 continue; /* error */
94
95 if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
96 break; /* success */
97
98 close(sock);
99 }
100
101 if (rp == NULL) {
102 err_nonfatal("Socket failed: %m");
103 sock = -1;
104 goto err;
105 }
106
107 setmysockopt(sock);
108 err:
109 freeaddrinfo(ai);
110 return sock;
111 }
112
openunix(const char * path)113 int openunix(const char *path) {
114 int sock;
115 struct sockaddr_un un_addr;
116 memset(&un_addr, 0, sizeof(un_addr));
117
118 un_addr.sun_family = AF_UNIX;
119 if (strnlen(path, sizeof(un_addr.sun_path)) == sizeof(un_addr.sun_path)) {
120 err_nonfatal("UNIX socket path too long");
121 return -1;
122 }
123
124 strncpy(un_addr.sun_path, path, sizeof(un_addr.sun_path) - 1);
125
126 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
127 err_nonfatal("SOCKET failed");
128 return -1;
129 };
130
131 if (connect(sock, &un_addr, sizeof(un_addr)) == -1) {
132 err_nonfatal("CONNECT failed");
133 close(sock);
134 return -1;
135 }
136 return sock;
137 }
138
send_request(int sock,uint32_t opt,ssize_t datasize,void * data)139 static void send_request(int sock, uint32_t opt, ssize_t datasize, void* data) {
140 struct {
141 uint64_t magic;
142 uint32_t opt;
143 uint32_t datasize;
144 } __attribute__((packed)) header = {
145 ntohll(opts_magic),
146 ntohl(opt),
147 ntohl(datasize),
148 };
149 if(datasize < 0) {
150 datasize = strlen((char*)data);
151 header.datasize = htonl(datasize);
152 }
153 writeit(sock, &header, sizeof(header));
154 if(data != NULL) {
155 writeit(sock, data, datasize);
156 }
157 }
158
send_info_request(int sock,uint32_t opt,int n_reqs,uint16_t * reqs,char * name)159 static void send_info_request(int sock, uint32_t opt, int n_reqs,
160 uint16_t* reqs, char* name) {
161 uint16_t rlen = htons(n_reqs);
162 uint32_t nlen = htonl(strlen(name));
163
164 send_request(sock, opt, sizeof(uint32_t) + strlen(name) + sizeof(uint16_t) + n_reqs * sizeof(uint16_t), NULL);
165 writeit(sock, &nlen, sizeof(nlen));
166 writeit(sock, name, strlen(name));
167 writeit(sock, &rlen, sizeof(rlen));
168 if(n_reqs > 0) {
169 writeit(sock, reqs, n_reqs * sizeof(uint16_t));
170 }
171 }
172
173 struct reply {
174 uint64_t magic;
175 uint32_t opt;
176 uint32_t reply_type;
177 uint32_t datasize;
178 char data[];
179 } __attribute__((packed));
180
read_reply(int sock)181 static struct reply* read_reply(int sock) {
182 struct reply *retval = (struct reply *)malloc(sizeof(struct reply));
183 readit(sock, retval, sizeof(*retval));
184 retval->magic = ntohll(retval->magic);
185 retval->opt = ntohl(retval->opt);
186 retval->reply_type = ntohl(retval->reply_type);
187 retval->datasize = ntohl(retval->datasize);
188 if (retval->magic != rep_magic) {
189 fprintf(stderr, "E: received invalid negotiation magic %" PRIu64 " (expected %" PRIu64 ")", retval->magic, rep_magic);
190 exit(EXIT_FAILURE);
191 }
192 if (retval->datasize > 0) {
193 retval = (struct reply *)realloc(retval, sizeof(struct reply) + retval->datasize);
194 readit(sock, &(retval->data), retval->datasize);
195 }
196 return retval;
197 }
198
ask_list(int sock)199 static void ask_list(int sock) {
200 uint32_t opt_server;
201 uint32_t len;
202 uint32_t lenn;
203 uint32_t reptype;
204 uint64_t magic;
205 int rlen;
206 #define BUF_SIZE 1024
207 char buf[BUF_SIZE];
208
209 send_request(sock, NBD_OPT_LIST, 0, NULL);
210 /* newline, move away from the "Negotiation:" line */
211 printf("\n");
212 do {
213 memset(buf, 0, 1024);
214 if(read(sock, &magic, sizeof(magic)) < 0) {
215 err("Reading magic from server: %m");
216 }
217 if(read(sock, &opt_server, sizeof(opt_server)) < 0) {
218 err("Reading option: %m");
219 }
220 if(read(sock, &reptype, sizeof(reptype)) <0) {
221 err("Reading reply from server: %m");
222 }
223 if(read(sock, &len, sizeof(len)) < 0) {
224 err("Reading length from server: %m");
225 }
226 magic=ntohll(magic);
227 len=ntohl(len);
228 reptype=ntohl(reptype);
229 if(magic != rep_magic) {
230 err("Not enough magic from server");
231 }
232 if(reptype & NBD_REP_FLAG_ERROR) {
233 switch(reptype) {
234 case NBD_REP_ERR_POLICY:
235 fprintf(stderr, "\nE: listing not allowed by server.\n");
236 break;
237 default:
238 fprintf(stderr, "\nE: unexpected error from server.\n");
239 break;
240 }
241 if(len > 0 && len < BUF_SIZE) {
242 if((rlen=read(sock, buf, len)) < 0) {
243 fprintf(stderr, "\nE: could not read error message from server\n");
244 } else {
245 buf[rlen] = '\0';
246 fprintf(stderr, "Server said: %s\n", buf);
247 }
248 }
249 exit(EXIT_FAILURE);
250 } else {
251 if(reptype != NBD_REP_ACK) {
252 if(reptype != NBD_REP_SERVER) {
253 err("Server sent us a reply we don't understand!");
254 }
255 if(read(sock, &lenn, sizeof(lenn)) < 0) {
256 fprintf(stderr, "\nE: could not read export name length from server\n");
257 exit(EXIT_FAILURE);
258 }
259 lenn=ntohl(lenn);
260 if (lenn >= BUF_SIZE) {
261 fprintf(stderr, "\nE: export name on server too long\n");
262 exit(EXIT_FAILURE);
263 }
264 if(read(sock, buf, lenn) < 0) {
265 fprintf(stderr, "\nE: could not read export name from server\n");
266 exit(EXIT_FAILURE);
267 }
268 buf[lenn] = 0;
269 printf("%s", buf);
270 len -= lenn;
271 len -= sizeof(lenn);
272 if(len > 0) {
273 if(read(sock, buf, len) < 0) {
274 fprintf(stderr, "\nE: could not read export description from server\n");
275 exit(EXIT_FAILURE);
276 }
277 buf[len] = 0;
278 printf(": %s\n", buf);
279 } else {
280 printf("\n");
281 }
282 }
283 }
284 } while(reptype != NBD_REP_ACK);
285 send_request(sock, NBD_OPT_ABORT, 0, NULL);
286 }
287
parse_sizes(char * buf,uint64_t * size,uint16_t * flags)288 static void parse_sizes(char *buf, uint64_t *size, uint16_t *flags) {
289 memcpy(size, buf, sizeof(*size));
290 *size = ntohll(*size);
291 buf += sizeof(*size);
292 memcpy(flags, buf, sizeof(*flags));
293 *flags = ntohs(*flags);
294
295 if ((*size>>12) > (uint64_t)~0UL) {
296 printf("size = %luMB", (unsigned long)(*size>>20));
297 err("Exported device is too big for me. Get 64-bit machine :-(\n");
298 } else {
299 printf("size = %luMB", (unsigned long)(*size>>20));
300 }
301 printf("\n");
302 }
303
send_opt_exportname(int sock,u64 * rsize64,uint16_t * flags,bool can_opt_go,char * name,uint16_t global_flags)304 static void send_opt_exportname(int sock, u64 *rsize64, uint16_t *flags,
305 bool can_opt_go, char* name, uint16_t global_flags) {
306 send_request(sock, NBD_OPT_EXPORT_NAME, -1, name);
307 char b[sizeof(*flags) + sizeof(*rsize64)];
308 if(readit(sock, b, sizeof(b)) < 0 && can_opt_go) {
309 err("E: server does not support NBD_OPT_GO and dropped connection after sending NBD_OPT_EXPORT_NAME. Try -g.");
310 }
311 parse_sizes(b, rsize64, flags);
312 if(!(global_flags & NBD_FLAG_NO_ZEROES)) {
313 char buf[125];
314 readit(sock, buf, 124);
315 }
316 }
317
318
negotiate(int * sockp,u64 * rsize64,uint16_t * flags,char * name,uint32_t needed_flags,uint32_t client_flags,uint32_t do_opts,char * certfile,char * keyfile,char * cacertfile,char * tlshostname,bool tls,bool can_opt_go)319 void negotiate(int *sockp, u64 *rsize64, uint16_t *flags, char* name,
320 uint32_t needed_flags, uint32_t client_flags, uint32_t do_opts,
321 char *certfile, char *keyfile, char *cacertfile,
322 char *tlshostname, bool tls, bool can_opt_go) {
323 u64 magic;
324 uint16_t tmp;
325 uint16_t global_flags;
326 char buf[256] = "\0\0\0\0\0\0\0\0\0";
327 int sock = *sockp;
328
329 printf("Negotiation: ");
330 readit(sock, buf, 8);
331 if (strcmp(buf, INIT_PASSWD))
332 err("INIT_PASSWD bad");
333 printf(".");
334 readit(sock, &magic, sizeof(magic));
335 magic = ntohll(magic);
336 if (magic != opts_magic) {
337 if(magic == cliserv_magic) {
338 err("It looks like you're trying to connect to an oldstyle server. This is no longer supported since nbd 3.10.");
339 }
340 }
341 printf(".");
342 readit(sock, &tmp, sizeof(uint16_t));
343 global_flags = ntohs(tmp);
344 if((needed_flags & global_flags) != needed_flags) {
345 /* There's currently really only one reason why this
346 * check could possibly fail, but we may need to change
347 * this error message in the future... */
348 fprintf(stderr, "\nE: Server does not support listing exports\n");
349 exit(EXIT_FAILURE);
350 }
351
352 if (global_flags & NBD_FLAG_NO_ZEROES) {
353 client_flags |= NBD_FLAG_C_NO_ZEROES;
354 }
355 client_flags = htonl(client_flags);
356 if (write(sock, &client_flags, sizeof(client_flags)) < 0)
357 err("Failed/2.1: %m");
358
359 #if HAVE_GNUTLS && !defined(NOTLS)
360 /* TLS */
361 if (tls) {
362 int plainfd[2]; // [0] is used by the proxy, [1] is used by NBD
363 tlssession_t *s = NULL;
364 int ret;
365 uint32_t tmp32;
366 uint64_t tmp64;
367
368 send_request(sock, NBD_OPT_STARTTLS, 0, NULL);
369
370 if (read(sock, &tmp64, sizeof(tmp64)) < 0)
371 err("Could not read cliserv_magic: %m");
372 tmp64 = ntohll(tmp64);
373 if (tmp64 != NBD_OPT_REPLY_MAGIC) {
374 err("reply magic does not match");
375 }
376 if (read(sock, &tmp32, sizeof(tmp32)) < 0)
377 err("Could not read option type: %m");
378 tmp32 = ntohl(tmp32);
379 if (tmp32 != NBD_OPT_STARTTLS)
380 err("Reply to wrong option");
381 if (read(sock, &tmp32, sizeof(tmp32)) < 0)
382 err("Could not read option reply type: %m");
383 tmp32 = ntohl(tmp32);
384 if (tmp32 != NBD_REP_ACK) {
385 err("Option reply type != NBD_REP_ACK");
386 }
387 if (read(sock, &tmp32, sizeof(tmp32)) < 0) err(
388 "Could not read option data length: %m");
389 tmp32 = ntohl(tmp32);
390 if (tmp32 != 0) {
391 err("Option reply data length != 0");
392 }
393 s = tlssession_new(0,
394 keyfile,
395 certfile,
396 cacertfile,
397 tlshostname,
398 !cacertfile || !tlshostname, // insecure flag
399 #ifdef DODBG
400 1, // debug
401 #else
402 0, // debug
403 #endif
404 NULL, // quitfn
405 NULL, // erroutfn
406 NULL // opaque
407 );
408 if (!s)
409 err("Cannot establish TLS session");
410
411 if (socketpair(AF_UNIX, SOCK_STREAM, 0, plainfd) < 0)
412 err("Cannot get socket pair");
413
414 if (set_nonblocking(plainfd[0], 0) <0 ||
415 set_nonblocking(plainfd[1], 0) <0 ||
416 set_nonblocking(sock, 0) <0) {
417 close(plainfd[0]);
418 close(plainfd[1]);
419 err("Cannot set socket options");
420 }
421
422 ret = fork();
423 if (ret < 0)
424 err("Could not fork");
425 else if (ret == 0) {
426 // we are the child
427 if (daemon(0, 0) < 0) {
428 /* no one will see this */
429 fprintf(stderr, "Can't detach from the terminal");
430 exit(1);
431 }
432 signal (SIGPIPE, SIG_IGN);
433 close(plainfd[1]);
434 tlssession_mainloop(sock, plainfd[0], s);
435 close(sock);
436 close(plainfd[0]);
437 exit(0);
438 }
439 close(plainfd[0]);
440 close(sock);
441 sock = plainfd[1]; /* use the decrypted FD from now on */
442 *sockp = sock;
443 }
444 #else
445 if (keyfile) {
446 err("TLS requested but support not compiled in");
447 }
448 #endif
449
450 if(do_opts & NBDC_DO_LIST) {
451 ask_list(sock);
452 exit(EXIT_SUCCESS);
453 }
454
455 struct reply *rep = NULL;
456
457 if(!can_opt_go) {
458 send_opt_exportname(sock, rsize64, flags, can_opt_go, name, global_flags);
459 return;
460 }
461
462 send_info_request(sock, NBD_OPT_GO, 0, NULL, name);
463
464 do {
465 if(rep != NULL) free(rep);
466 rep = read_reply(sock);
467 if(rep && (rep->reply_type & NBD_REP_FLAG_ERROR)) {
468 switch(rep->reply_type) {
469 case NBD_REP_ERR_UNSUP:
470 /* server doesn't support NBD_OPT_GO or NBD_OPT_INFO,
471 * fall back to NBD_OPT_EXPORT_NAME */
472 send_opt_exportname(sock, rsize64, flags, can_opt_go, name, global_flags);
473 free(rep);
474 return;
475 case NBD_REP_ERR_POLICY:
476 if(rep->datasize > 0) {
477 char errstr[1024];
478 snprintf(errstr, sizeof errstr, "Connection not allowed by server policy. Server said: %s", rep->data);
479 err(errstr);
480 } else {
481 err("Connection not allowed by server policy.");
482 }
483 free(rep);
484 exit(EXIT_FAILURE);
485 default:
486 if(rep->datasize > 0) {
487 char errstr[1024];
488 snprintf(errstr, sizeof errstr, "Unknown error returned by server. Server said: %s", rep->data);
489 err(errstr);
490 } else {
491 err("Unknown error returned by server.");
492 }
493 free(rep);
494 exit(EXIT_FAILURE);
495 }
496 }
497 uint16_t info_type;
498 switch(rep->reply_type) {
499 case NBD_REP_INFO:
500 memcpy(&info_type, rep->data, 2);
501 info_type = htons(info_type);
502 switch(info_type) {
503 case NBD_INFO_EXPORT:
504 parse_sizes(rep->data + 2, rsize64, flags);
505 break;
506 default:
507 // ignore these, don't need them
508 break;
509 }
510 break;
511 case NBD_REP_ACK:
512 break;
513 default:
514 err_nonfatal("Unknown reply to NBD_OPT_GO received, ignoring");
515 }
516 } while(rep->reply_type != NBD_REP_ACK);
517 free(rep);
518 }
519