Network Block Device  @PACKAGE_VERSION@
nbdsrv.c
Go to the documentation of this file.
1 #include "config.h"
2 #include "nbd-debug.h"
3 
4 #include <nbdsrv.h>
5 
6 #include <assert.h>
7 #include <ctype.h>
8 #include <netdb.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <syslog.h>
13 #include <unistd.h>
14 
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 
19 #define LINELEN 256 /**< Size of static buffer used to read the
20  authorization file (yuck) */
21 
22 #include <cliserv.h>
23 
24 bool address_matches(const char* mask, const struct sockaddr* addr, GError** err) {
25  struct addrinfo *res, *aitmp, hints;
26  char *masksep;
27  char privmask[strlen(mask)+1];
28  int masklen;
29  int addrlen = addr->sa_family == AF_INET ? 4 : 16;
30 
31  assert(addr->sa_family == AF_INET || addr->sa_family == AF_INET6);
32 
33  strcpy(privmask, mask);
34 
35  memset(&hints, 0, sizeof(hints));
36  hints.ai_family = AF_UNSPEC;
37  hints.ai_flags = AI_NUMERICHOST;
38 
39  if((masksep = strchr(privmask, '/'))) {
40  *masksep = '\0';
41  masklen = strtol(++masksep, NULL, 10);
42  } else {
43  masklen = addrlen * 8;
44  }
45 
46  int e;
47  if((e = getaddrinfo(privmask, NULL, &hints, &res))) {
48  g_set_error(err, NBDS_ERR, NBDS_ERR_GAI, "could not parse netmask line: %s", gai_strerror(e));
49  return false;
50  }
51  aitmp = res;
52  while(res) {
53  const uint8_t* byte_s;
54  uint8_t* byte_t;
55  uint8_t mask = 0;
56  int len_left = masklen;
57  if(res->ai_family != addr->sa_family) {
58  goto next;
59  }
60  switch(addr->sa_family) {
61  case AF_INET:
62  byte_s = (const uint8_t*)(&(((struct sockaddr_in*)addr)->sin_addr));
63  byte_t = (uint8_t*)(&(((struct sockaddr_in*)(res->ai_addr))->sin_addr));
64  break;
65  case AF_INET6:
66  byte_s = (const uint8_t*)(&(((struct sockaddr_in6*)addr)->sin6_addr));
67  byte_t = (uint8_t*)(&(((struct sockaddr_in6*)(res->ai_addr))->sin6_addr));
68  break;
69  }
70  while(len_left >= 8) {
71  if(*byte_s != *byte_t) {
72  goto next;
73  }
74  byte_s++; byte_t++;
75  len_left -= 8;
76  }
77  if(len_left) {
78  mask = getmaskbyte(len_left);
79  if((*byte_s & mask) != (*byte_t & mask)) {
80  goto next;
81  }
82  }
83  freeaddrinfo(aitmp);
84  return true;
85  next:
86  res = res->ai_next;
87  }
88  freeaddrinfo(aitmp);
89  return false;
90 }
91 
92 uint8_t getmaskbyte(int masklen) {
93  if(masklen >= 8) {
94  return 0xFF;
95  }
96  uint8_t retval = 0;
97  for(int i = 7; i + masklen > 7; i--) {
98  retval |= 1 << i;
99  }
100 
101  return retval;
102 }
103 
104 int authorized_client(CLIENT *opts) {
105  FILE *f ;
106  char line[LINELEN];
107 
108  if (opts->server->authname == NULL) {
109  msg(LOG_INFO, "No authorization file, granting access.");
110  return 1;
111  }
112 
113  if ((f=fopen(opts->server->authname,"r"))==NULL) {
114  msg(LOG_INFO, "Can't open authorization file %s (%s).",
115  opts->server->authname, strerror(errno));
116  return 1 ;
117  }
118 
119  while (fgets(line,LINELEN,f)!=NULL) {
120  char* pos;
121  /* Drop comments */
122  if((pos = strchr(line, '#'))) {
123  *pos = '\0';
124  }
125  /* Skip whitespace */
126  pos = line;
127  while((*pos) && isspace(*pos)) {
128  pos++;
129  }
130  /* Skip content-free lines */
131  if(!(*pos)) {
132  continue;
133  }
134  if(address_matches(line, (struct sockaddr*)&opts->clientaddr, NULL)) {
135  fclose(f);
136  return 1;
137  }
138  }
139  fclose(f);
140  return 0;
141 }
142 
143 /**
144  * duplicate server
145  * @param s the old server we want to duplicate
146  * @return new duplicated server
147  **/
148 SERVER* dup_serve(const SERVER *const s) {
149  SERVER *serve = NULL;
150 
151  serve=g_new0(SERVER, 1);
152  if(serve == NULL)
153  return NULL;
154 
155  if(s->exportname)
156  serve->exportname = g_strdup(s->exportname);
157 
158  serve->expected_size = s->expected_size;
159 
160  if(s->listenaddr)
161  serve->listenaddr = g_strdup(s->listenaddr);
162 
163  serve->port = s->port;
164 
165  if(s->authname)
166  serve->authname = strdup(s->authname);
167 
168  serve->flags = s->flags;
169  serve->socket = s->socket;
170  serve->socket_family = s->socket_family;
171  serve->virtstyle = s->virtstyle;
172  serve->cidrlen = s->cidrlen;
173 
174  if(s->prerun)
175  serve->prerun = g_strdup(s->prerun);
176 
177  if(s->postrun)
178  serve->postrun = g_strdup(s->postrun);
179 
180  if(s->transactionlog)
181  serve->transactionlog = g_strdup(s->transactionlog);
182 
183  if(s->servename)
184  serve->servename = g_strdup(s->servename);
185 
186  serve->max_connections = s->max_connections;
187 
188  return serve;
189 }
190 
191 int append_serve(const SERVER *const s, GArray *const a) {
192  SERVER *ns = NULL;
193  struct addrinfo hints;
194  struct addrinfo *ai = NULL;
195  struct addrinfo *rp = NULL;
196  char host[NI_MAXHOST];
197  gchar *port = NULL;
198  int e;
199  int ret;
200 
201  assert(s != NULL);
202  if(a == NULL) {
203  return -1;
204  }
205 
206  port = g_strdup_printf("%d", s->port);
207 
208  memset(&hints,'\0',sizeof(hints));
209  hints.ai_family = AF_UNSPEC;
210  hints.ai_socktype = SOCK_STREAM;
211  hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
212  hints.ai_protocol = IPPROTO_TCP;
213 
214  e = getaddrinfo(s->listenaddr, port, &hints, &ai);
215 
216  if (port)
217  g_free(port);
218 
219  if(e == 0) {
220  for (rp = ai; rp != NULL; rp = rp->ai_next) {
221  e = getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
222 
223  if (e != 0) { // error
224  fprintf(stderr, "getnameinfo: %s\n", gai_strerror(e));
225  continue;
226  }
227 
228  // duplicate server and set listenaddr to resolved IP address
229  ns = dup_serve (s);
230  if (ns) {
231  ns->listenaddr = g_strdup(host);
232  ns->socket_family = rp->ai_family;
233  g_array_append_val(a, *ns);
234  free(ns);
235  ns = NULL;
236  }
237  }
238 
239  ret = 0;
240  } else {
241  fprintf(stderr, "getaddrinfo failed on listen host/address: %s (%s)\n", s->listenaddr ? s->listenaddr : "any", gai_strerror(e));
242  ret = -1;
243  }
244 
245  if (ai)
246  freeaddrinfo(ai);
247 
248  return ret;
249 }
250 
251 uint64_t size_autodetect(int fhandle) {
252  off_t es;
253  u64 bytes __attribute__((unused));
254  struct stat stat_buf;
255  int error;
256 
257 #ifdef HAVE_SYS_MOUNT_H
258 #ifdef HAVE_SYS_IOCTL_H
259 #ifdef BLKGETSIZE64
260  DEBUG("looking for export size with ioctl BLKGETSIZE64\n");
261  if (!ioctl(fhandle, BLKGETSIZE64, &bytes) && bytes) {
262  return bytes;
263  }
264 #endif /* BLKGETSIZE64 */
265 #endif /* HAVE_SYS_IOCTL_H */
266 #endif /* HAVE_SYS_MOUNT_H */
267 
268  DEBUG("looking for fhandle size with fstat\n");
269  stat_buf.st_size = 0;
270  error = fstat(fhandle, &stat_buf);
271  if (!error) {
272  /* always believe stat if a regular file as it might really
273  * be zero length */
274  if (S_ISREG(stat_buf.st_mode) || (stat_buf.st_size > 0))
275  return (uint64_t)stat_buf.st_size;
276  } else {
277  DEBUG("fstat failed: %s", strerror(errno));
278  }
279 
280  DEBUG("looking for fhandle size with lseek SEEK_END\n");
281  es = lseek(fhandle, (off_t)0, SEEK_END);
282  if (es > ((off_t)0)) {
283  return (uint64_t)es;
284  } else {
285  DEBUG("lseek failed: %d", errno==EBADF?1:(errno==ESPIPE?2:(errno==EINVAL?3:4)));
286  }
287 
288  DEBUG("Could not find size of exported block device: %s", strerror(errno));
289  return UINT64_MAX;
290 }
291 
gchar * servename
name of the export as selected by nbd-client
Definition: nbdsrv.h:46
Variables associated with a server.
Definition: nbdsrv.h:29
uint8_t getmaskbyte(int masklen)
Gets a byte to allow for address masking.
Definition: nbdsrv.c:93
void err(const char *s)
Definition: cliserv.c:56
SERVER * server
The server this client is getting data from.
Definition: nbdsrv.h:64
gchar * postrun
command that will be ran after the client disconnects
Definition: nbdsrv.h:44
#define msg(prio,...)
Logging macros.
Definition: nbdsrv.h:117
bool address_matches(const char *mask, const struct sockaddr *addr, GError **err)
Check whether a given address matches a given netmask.
Definition: nbdsrv.c:25
struct sockaddr_storage clientaddr
peer, in binary format, network byte order
Definition: nbdsrv.h:58
int flags
flags associated with this exported file
Definition: nbdsrv.h:36
gchar * exportname
(unprocessed) filename of the file we&#39;re exporting
Definition: nbdsrv.h:30
unsigned int port
port we&#39;re exporting this file at
Definition: nbdsrv.h:34
gchar * transactionlog
filename for transaction log
Definition: nbdsrv.h:48
gchar * listenaddr
The IP address we&#39;re listening on.
Definition: nbdsrv.h:33
int socket
The socket of this server.
Definition: nbdsrv.h:37
Variables associated with a client connection.
Definition: nbdsrv.h:55
struct nbd_reply __attribute__
Failed to get address info.
Definition: nbdsrv.h:101
SERVER * dup_serve(const SERVER *const s)
duplicate server
Definition: nbdsrv.c:149
uint64_t size_autodetect(int fhandle)
Detect the size of a file.
Definition: nbdsrv.c:252
int max_connections
maximum number of opened connections
Definition: nbdsrv.h:47
VIRT_STYLE virtstyle
The style of virtualization, if any.
Definition: nbdsrv.h:39
int append_serve(const SERVER *const s, GArray *const a)
append new server to array
Definition: nbdsrv.c:192
int socket_family
family of the socket
Definition: nbdsrv.h:38
uint64_t expected_size
size of the exported file as it was told to us through configuration
Definition: nbdsrv.h:31
gchar * prerun
command to be ran after connecting a client, but before starting to serve
Definition: nbdsrv.h:42
#define DEBUG(...)
Definition: nbd-debug.h:8
char * authname
filename of the authorization file
Definition: nbdsrv.h:35
#define LINELEN
Size of static buffer used to read the authorization file (yuck)
Definition: nbdsrv.c:19
#define NBDS_ERR
Error domain common for all NBD server errors.
Definition: nbdsrv.h:81
uint8_t cidrlen
The length of the mask when we use CIDR-style virtualization.
Definition: nbdsrv.h:40
int authorized_client(CLIENT *opts)
Check whether a client is allowed to connect.
Definition: nbdsrv.c:105