16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <treefiles.h>
20 #ifdef HAVE_SYS_MOUNT_H
21 #include <sys/mount.h>
24 #define LINELEN 256 /**< Size of static buffer used to read the
25 authorization file (yuck) */
29 bool address_matches(const char* mask
, const struct sockaddr
* addr
, GError
** err
) {
30 struct addrinfo
*res
, *aitmp
, hints
;
32 char privmask
[strlen(mask
)+1];
34 int addrlen
= addr
->sa_family
== AF_INET
? 4 : 16;
36 assert(addr
->sa_family
== AF_INET
|| addr
->sa_family
== AF_INET6
);
38 strcpy(privmask
, mask
);
40 memset(&hints
, 0, sizeof(hints
));
41 hints
.ai_family
= AF_UNSPEC
;
42 hints
.ai_flags
= AI_NUMERICHOST
;
44 if((masksep
= strchr(privmask
, '/'))) {
46 masklen
= strtol(++masksep
, NULL
, 10);
48 masklen
= addrlen
* 8;
52 if((e
= getaddrinfo(privmask
, NULL
, &hints
, &res
))) {
53 g_set_error(err
, NBDS_ERR
, NBDS_ERR_GAI
, "could not parse netmask line: %s", gai_strerror(e
));
58 const uint8_t* byte_s
;
61 int len_left
= masklen
;
62 if(res
->ai_family
!= addr
->sa_family
) {
63 msg(LOG_DEBUG
, "client address does not match %d/%d: address family mismatch (IPv4 vs IPv6?)",
64 (int)res
->ai_family
, (int)addr
->sa_family
);
67 switch(addr
->sa_family
) {
69 byte_s
= (const uint8_t*)(&(((struct sockaddr_in
*)addr
)->sin_addr
));
70 byte_t
= (uint8_t*)(&(((struct sockaddr_in
*)(res
->ai_addr
))->sin_addr
));
73 byte_s
= (const uint8_t*)(&(((struct sockaddr_in6
*)addr
)->sin6_addr
));
74 byte_t
= (uint8_t*)(&(((struct sockaddr_in6
*)(res
->ai_addr
))->sin6_addr
));
77 while(len_left
>= 8) {
78 if(*byte_s
!= *byte_t
) {
85 mask
= getmaskbyte(len_left
);
86 if((*byte_s
& mask
) != (*byte_t
& mask
)) {
99 uint8_t getmaskbyte(int masklen
) {
104 for(int i
= 7; i
+ masklen
> 7; i
--) {
111 int authorized_client(CLIENT
*opts
) {
115 if (opts
->server
->authname
== NULL
) {
116 msg(LOG_INFO
, "No authorization file, granting access.");
120 if ((f
=fopen(opts
->server
->authname
,"r"))==NULL
) {
121 msg(LOG_INFO
, "Can't open authorization file %s (%s).",
122 opts
->server
->authname
, strerror(errno
));
126 while (fgets(line
,LINELEN
,f
)!=NULL
) {
129 if((pos
= strchr(line
, '#'))) {
132 /* Skip whitespace */
134 while((*pos
) && isspace(*pos
)) {
137 /* Skip content-free lines */
141 if(address_matches(line
, (struct sockaddr
*)&opts
->clientaddr
, NULL
)) {
152 * @param s the old server we want to duplicate
153 * @return new duplicated server
155 SERVER
* dup_serve(const SERVER
*const s
) {
156 SERVER
*serve
= NULL
;
158 serve
=g_new0(SERVER
, 1);
163 serve
->exportname
= g_strdup(s
->exportname
);
165 serve
->expected_size
= s
->expected_size
;
168 serve
->listenaddr
= g_strdup(s
->listenaddr
);
171 serve
->authname
= g_strdup(s
->authname
);
173 serve
->flags
= s
->flags
;
174 serve
->virtstyle
= s
->virtstyle
;
175 serve
->cidrlen
= s
->cidrlen
;
178 serve
->prerun
= g_strdup(s
->prerun
);
181 serve
->postrun
= g_strdup(s
->postrun
);
183 if(s
->transactionlog
)
184 serve
->transactionlog
= g_strdup(s
->transactionlog
);
187 serve
->servename
= g_strdup(s
->servename
);
190 serve
->cowdir
= g_strdup(s
->cowdir
);
192 serve
->max_connections
= s
->max_connections
;
197 uint64_t size_autodetect(int fhandle
) {
199 u64 bytes
__attribute__((unused
));
200 struct stat stat_buf
;
203 #ifdef HAVE_SYS_MOUNT_H
204 #ifdef HAVE_SYS_IOCTL_H
206 DEBUG("looking for export size with ioctl BLKGETSIZE64\n");
207 if (!ioctl(fhandle
, BLKGETSIZE64
, &bytes
) && bytes
) {
210 #endif /* BLKGETSIZE64 */
211 #endif /* HAVE_SYS_IOCTL_H */
212 #endif /* HAVE_SYS_MOUNT_H */
214 DEBUG("looking for fhandle size with fstat\n");
215 stat_buf
.st_size
= 0;
216 error
= fstat(fhandle
, &stat_buf
);
218 /* always believe stat if a regular file as it might really
220 if (S_ISREG(stat_buf
.st_mode
) || (stat_buf
.st_size
> 0))
221 return (uint64_t)stat_buf
.st_size
;
223 DEBUG("fstat failed: %s", strerror(errno
));
226 DEBUG("looking for fhandle size with lseek SEEK_END\n");
227 es
= lseek(fhandle
, (off_t
)0, SEEK_END
);
228 if (es
> ((off_t
)0)) {
231 DEBUG("lseek failed: %d", errno
==EBADF
?1:(errno
==ESPIPE
?2:(errno
==EINVAL
?3:4)));
234 DEBUG("Could not find size of exported block device: %s", strerror(errno
));
238 int exptrim(struct nbd_request
* req
, CLIENT
* client
) {
239 /* Caller did range checking */
240 assert(!(client
->server
->flags
& F_READONLY
));
241 assert(req
->from
+ req
->len
<= client
->exportsize
);
242 /* For copy-on-write, we should trim on the diff file. Not yet
244 if(client
->server
->flags
& F_COPYONWRITE
) {
245 DEBUG("TRIM not supported yet on copy-on-write exports");
248 if (client
->server
->flags
& F_TREEFILES
) {
249 /* start address of first block to be trimmed */
250 off_t min
= ( ( req
->from
+ TREEPAGESIZE
- 1 ) / TREEPAGESIZE
) * TREEPAGESIZE
;
251 /* start address of first block NOT to be trimmed */
252 off_t max
= ( ( req
->from
+ req
->len
) / TREEPAGESIZE
) * TREEPAGESIZE
;
254 delete_treefile(client
->exportname
,client
->exportsize
,min
);
257 DEBUG("Performed TRIM request on TREE structure from %llu to %llu", (unsigned long long) req
->from
, (unsigned long long) req
->len
);
260 FILE_INFO cur
= g_array_index(client
->export
, FILE_INFO
, 0);
264 if(i
<client
->export
->len
) {
265 next
= g_array_index(client
->export
, FILE_INFO
, i
);
268 next
.startoff
= client
->exportsize
;
270 if(cur
.startoff
<= req
->from
&& next
.startoff
- cur
.startoff
>= req
->len
) {
271 off_t reqoff
= req
->from
- cur
.startoff
;
272 off_t curlen
= next
.startoff
- reqoff
;
273 off_t reqlen
= curlen
- reqoff
> req
->len
? req
->len
: curlen
- reqoff
;
274 punch_hole(cur
.fhandle
, reqoff
, reqlen
);
278 } while(i
< client
->export
->len
&& cur
.startoff
< (req
->from
+ req
->len
));
279 DEBUG("Performed TRIM request from %llu to %llu", (unsigned long long) req
->from
, (unsigned long long) req
->len
);