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