1 /*- 2 * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <stdint.h> 32 #include <unistd.h> 33 #include <fcntl.h> 34 #include <sys/param.h> 35 #include <sys/queue.h> 36 #include <sys/endian.h> 37 #include <sys/socket.h> 38 #include <sys/ioctl.h> 39 #include <sys/stat.h> 40 #include <sys/time.h> 41 #include <sys/disk.h> 42 #include <sys/bio.h> 43 #include <netinet/in.h> 44 #include <netinet/tcp.h> 45 #include <arpa/inet.h> 46 #include <signal.h> 47 #include <err.h> 48 #include <errno.h> 49 #include <string.h> 50 #include <libgen.h> 51 #include <syslog.h> 52 #include <stdarg.h> 53 54 #include <geom/gate/g_gate.h> 55 #include "ggate.h" 56 57 58 #define G_GATED_EXPORT_FILE "/etc/gg.exports" 59 #define G_GATED_DEBUG(...) \ 60 if (g_gate_verbose) { \ 61 printf(__VA_ARGS__); \ 62 printf("\n"); \ 63 } 64 65 static const char *exports = G_GATED_EXPORT_FILE; 66 static int got_sighup = 0; 67 static int nagle = 1; 68 static unsigned rcvbuf = G_GATE_RCVBUF; 69 static unsigned sndbuf = G_GATE_SNDBUF; 70 71 struct export { 72 char *e_path; /* path to device/file */ 73 in_addr_t e_ip; /* remote IP address */ 74 in_addr_t e_mask; /* IP mask */ 75 unsigned e_flags; /* flags (RO/RW) */ 76 SLIST_ENTRY(export) e_next; 77 }; 78 static SLIST_HEAD(, export) exports_list = 79 SLIST_HEAD_INITIALIZER(&exports_list); 80 81 static void 82 usage(void) 83 { 84 85 fprintf(stderr, "usage: %s [-nv] [-a address] [-p port] [-R rcvbuf] " 86 "[-S sndbuf] [exports file]\n", getprogname()); 87 exit(EXIT_FAILURE); 88 } 89 90 static char * 91 ip2str(in_addr_t ip) 92 { 93 static char sip[16]; 94 95 snprintf(sip, sizeof(sip), "%u.%u.%u.%u", 96 ((ip >> 24) & 0xff), 97 ((ip >> 16) & 0xff), 98 ((ip >> 8) & 0xff), 99 (ip & 0xff)); 100 return (sip); 101 } 102 103 static in_addr_t 104 countmask(unsigned m) 105 { 106 in_addr_t mask; 107 108 if (m == 0) { 109 mask = 0x0; 110 } else { 111 mask = 1 << (32 - m); 112 mask--; 113 mask = ~mask; 114 } 115 return (mask); 116 } 117 118 static void 119 line_parse(char *line, unsigned lineno) 120 { 121 struct export *ex; 122 char *word, *path, *sflags; 123 unsigned flags, i, vmask; 124 in_addr_t ip, mask; 125 126 ip = mask = flags = vmask = 0; 127 path = NULL; 128 sflags = NULL; 129 130 for (i = 0, word = strtok(line, " \t"); word != NULL; 131 i++, word = strtok(NULL, " \t")) { 132 switch (i) { 133 case 0: /* IP address or host name */ 134 ip = g_gate_str2ip(strsep(&word, "/")); 135 if (ip == INADDR_NONE) { 136 g_gate_xlog("Invalid IP/host name at line %u.", 137 lineno); 138 } 139 ip = ntohl(ip); 140 if (word == NULL) 141 vmask = 32; 142 else { 143 errno = 0; 144 vmask = strtoul(word, NULL, 10); 145 if (vmask == 0 && errno != 0) { 146 g_gate_xlog("Invalid IP mask value at " 147 "line %u.", lineno); 148 } 149 if ((unsigned)vmask > 32) { 150 g_gate_xlog("Invalid IP mask value at line %u.", 151 lineno); 152 } 153 } 154 mask = countmask(vmask); 155 break; 156 case 1: /* flags */ 157 if (strcasecmp("rd", word) == 0 || 158 strcasecmp("ro", word) == 0) { 159 flags = O_RDONLY; 160 } else if (strcasecmp("wo", word) == 0) { 161 flags = O_WRONLY; 162 } else if (strcasecmp("rw", word) == 0) { 163 flags = O_RDWR; 164 } else { 165 g_gate_xlog("Invalid value in flags field at " 166 "line %u.", lineno); 167 } 168 sflags = word; 169 break; 170 case 2: /* path */ 171 if (strlen(word) >= MAXPATHLEN) { 172 g_gate_xlog("Path too long at line %u. ", 173 lineno); 174 } 175 path = word; 176 break; 177 default: 178 g_gate_xlog("Too many arguments at line %u. ", lineno); 179 } 180 } 181 if (i != 3) 182 g_gate_xlog("Too few arguments at line %u.", lineno); 183 184 ex = malloc(sizeof(*ex)); 185 if (ex == NULL) 186 g_gate_xlog("No enough memory."); 187 ex->e_path = strdup(path); 188 if (ex->e_path == NULL) 189 g_gate_xlog("No enough memory."); 190 191 /* Made 'and' here. */ 192 ex->e_ip = (ip & mask); 193 ex->e_mask = mask; 194 ex->e_flags = flags; 195 196 SLIST_INSERT_HEAD(&exports_list, ex, e_next); 197 198 g_gate_log(LOG_DEBUG, "Added %s/%u %s %s to exports list.", 199 ip2str(ex->e_ip), vmask, path, sflags); 200 } 201 202 static void 203 exports_clear(void) 204 { 205 struct export *ex; 206 207 while (!SLIST_EMPTY(&exports_list)) { 208 ex = SLIST_FIRST(&exports_list); 209 SLIST_REMOVE_HEAD(&exports_list, e_next); 210 free(ex); 211 } 212 } 213 214 #define EXPORTS_LINE_SIZE 2048 215 static void 216 exports_get(void) 217 { 218 char buf[EXPORTS_LINE_SIZE], *line; 219 unsigned lineno = 0, objs = 0, len; 220 FILE *fd; 221 222 exports_clear(); 223 224 fd = fopen(exports, "r"); 225 if (fd == NULL) { 226 g_gate_xlog("Cannot open exports file (%s): %s.", exports, 227 strerror(errno)); 228 } 229 230 g_gate_log(LOG_INFO, "Reading exports file (%s).", exports); 231 232 for (;;) { 233 if (fgets(buf, sizeof(buf), fd) == NULL) { 234 if (feof(fd)) 235 break; 236 237 g_gate_xlog("Error while reading exports file: %s.", 238 strerror(errno)); 239 } 240 241 /* Increase line count. */ 242 lineno++; 243 244 /* Skip spaces and tabs. */ 245 for (line = buf; *line == ' ' || *line == '\t'; ++line) 246 ; 247 248 /* Empty line, comment or empty line at the end of file. */ 249 if (*line == '\n' || *line == '#' || *line == '\0') 250 continue; 251 252 len = strlen(line); 253 if (line[len - 1] == '\n') { 254 /* Remove new line char. */ 255 line[len - 1] = '\0'; 256 } else { 257 if (!feof(fd)) 258 g_gate_xlog("Line %u too long.", lineno); 259 } 260 261 line_parse(line, lineno); 262 objs++; 263 } 264 265 fclose(fd); 266 267 if (objs == 0) 268 g_gate_xlog("There are no objects to export."); 269 270 g_gate_log(LOG_INFO, "Exporting %u object(s).", objs); 271 } 272 273 static struct export * 274 exports_find(struct sockaddr *s, const char *path) 275 { 276 struct export *ex; 277 in_addr_t ip; 278 279 ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr); 280 SLIST_FOREACH(ex, &exports_list, e_next) { 281 if ((ip & ex->e_mask) != ex->e_ip) 282 continue; 283 if (path != NULL && strcmp(path, ex->e_path) != 0) 284 continue; 285 286 g_gate_log(LOG_INFO, "Connection from: %s.", ip2str(ip)); 287 return (ex); 288 } 289 g_gate_log(LOG_INFO, "Unauthorized connection from: %s.", ip2str(ip)); 290 291 return (NULL); 292 } 293 294 static void 295 sendfail(int sfd, int error, const char *fmt, ...) 296 { 297 struct g_gate_sinit sinit; 298 va_list ap; 299 int data; 300 301 sinit.gs_error = error; 302 g_gate_swap2n_sinit(&sinit); 303 data = send(sfd, &sinit, sizeof(sinit), 0); 304 g_gate_swap2h_sinit(&sinit); 305 if (data == -1) { 306 g_gate_xlog("Error while sending initial packet: %s.", 307 strerror(errno)); 308 } 309 if (fmt != NULL) { 310 va_start(ap, fmt); 311 g_gate_xvlog(fmt, ap); 312 /* NOTREACHED */ 313 va_end(ap); 314 } 315 exit(EXIT_FAILURE); 316 } 317 318 static void 319 serve(int sfd, struct sockaddr *s) 320 { 321 struct g_gate_cinit cinit; 322 struct g_gate_sinit sinit; 323 struct g_gate_hdr hdr; 324 struct export *ex; 325 char ipmask[32]; /* 32 == strlen("xxx.xxx.xxx.xxx/xxx.xxx.xxx.xxx")+1 */ 326 size_t bufsize; 327 int32_t error; 328 int fd, flags; 329 ssize_t data; 330 char *buf; 331 332 g_gate_log(LOG_DEBUG, "Receiving initial packet."); 333 data = recv(sfd, &cinit, sizeof(cinit), MSG_WAITALL); 334 g_gate_swap2h_cinit(&cinit); 335 if (data == -1) { 336 g_gate_xlog("Error while receiving initial packet: %s.", 337 strerror(errno)); 338 } 339 340 ex = exports_find(s, cinit.gc_path); 341 if (ex == NULL) { 342 sendfail(sfd, EINVAL, "Requested path isn't exported: %s.", 343 strerror(errno)); 344 } 345 346 error = 0; 347 strlcpy(ipmask, ip2str(ex->e_ip), sizeof(ipmask)); 348 strlcat(ipmask, "/", sizeof(ipmask)); 349 strlcat(ipmask, ip2str(ex->e_mask), sizeof(ipmask)); 350 if ((cinit.gc_flags & G_GATE_FLAG_READONLY) != 0) { 351 if (ex->e_flags == O_WRONLY) { 352 g_gate_log(LOG_ERR, "Read-only access requested, but " 353 "%s (%s) is exported write-only.", ex->e_path, 354 ipmask); 355 error = EPERM; 356 } else { 357 sinit.gs_flags = G_GATE_FLAG_READONLY; 358 } 359 } else if ((cinit.gc_flags & G_GATE_FLAG_WRITEONLY) != 0) { 360 if (ex->e_flags == O_RDONLY) { 361 g_gate_log(LOG_ERR, "Write-only access requested, but " 362 "%s (%s) is exported read-only.", ex->e_path, 363 ipmask); 364 error = EPERM; 365 } else { 366 sinit.gs_flags = G_GATE_FLAG_WRITEONLY; 367 } 368 } else { 369 if (ex->e_flags == O_RDONLY) { 370 g_gate_log(LOG_ERR, "Read-write access requested, but " 371 "%s (%s) is exported read-only.", ex->e_path, 372 ipmask); 373 error = EPERM; 374 } else if (ex->e_flags == O_WRONLY) { 375 g_gate_log(LOG_ERR, "Read-write access requested, but " 376 "%s (%s) is exported write-only.", ex->e_path, 377 ipmask); 378 error = EPERM; 379 } else { 380 sinit.gs_flags = 0; 381 } 382 } 383 if (error != 0) 384 sendfail(sfd, error, NULL); 385 flags = g_gate_openflags(sinit.gs_flags); 386 fd = open(ex->e_path, flags); 387 if (fd < 0) { 388 sendfail(sfd, errno, "Error while opening %s: %s.", ex->e_path, 389 strerror(errno)); 390 } 391 392 g_gate_log(LOG_DEBUG, "Sending initial packet."); 393 /* 394 * This field isn't used by ggc(8) for now. 395 * It should be used in future when user don't give device size. 396 */ 397 sinit.gs_mediasize = g_gate_mediasize(fd); 398 sinit.gs_sectorsize = g_gate_sectorsize(fd); 399 sinit.gs_error = 0; 400 g_gate_swap2n_sinit(&sinit); 401 data = send(sfd, &sinit, sizeof(sinit), 0); 402 g_gate_swap2h_sinit(&sinit); 403 if (data == -1) { 404 sendfail(sfd, errno, "Error while sending initial packet: %s.", 405 strerror(errno)); 406 } 407 408 bufsize = G_GATE_BUFSIZE_START; 409 buf = malloc(bufsize); 410 if (buf == NULL) 411 g_gate_xlog("No enough memory."); 412 413 g_gate_log(LOG_DEBUG, "New process: %u.", getpid()); 414 415 for (;;) { 416 /* 417 * Receive request. 418 */ 419 data = recv(sfd, &hdr, sizeof(hdr), MSG_WAITALL); 420 if (data == 0) { 421 g_gate_log(LOG_DEBUG, "Process %u exiting.", getpid()); 422 exit(EXIT_SUCCESS); 423 } else if (data == -1) { 424 g_gate_xlog("Error while receiving hdr packet: %s.", 425 strerror(errno)); 426 } else if (data != sizeof(hdr)) { 427 g_gate_xlog("Malformed hdr packet received."); 428 } 429 g_gate_log(LOG_DEBUG, "Received hdr packet."); 430 g_gate_swap2h_hdr(&hdr); 431 432 /* 433 * Increase buffer if there is need to. 434 */ 435 if (hdr.gh_length > bufsize) { 436 bufsize = hdr.gh_length; 437 g_gate_log(LOG_DEBUG, "Increasing buffer to %u.", 438 bufsize); 439 buf = realloc(buf, bufsize); 440 if (buf == NULL) 441 g_gate_xlog("No enough memory."); 442 } 443 444 if (hdr.gh_cmd == BIO_READ) { 445 if (pread(fd, buf, hdr.gh_length, 446 hdr.gh_offset) == -1) { 447 error = errno; 448 g_gate_log(LOG_ERR, "Error while reading data " 449 "(offset=%ju, size=%zu): %s.", 450 (uintmax_t)hdr.gh_offset, 451 (size_t)hdr.gh_length, strerror(error)); 452 } else { 453 error = 0; 454 } 455 hdr.gh_error = error; 456 g_gate_swap2n_hdr(&hdr); 457 if (send(sfd, &hdr, sizeof(hdr), 0) == -1) { 458 g_gate_xlog("Error while sending status: %s.", 459 strerror(errno)); 460 } 461 g_gate_swap2h_hdr(&hdr); 462 /* Send data only if there was no error while pread(). */ 463 if (error == 0) { 464 data = send(sfd, buf, hdr.gh_length, 0); 465 if (data == -1) { 466 g_gate_xlog("Error while sending data: " 467 "%s.", strerror(errno)); 468 } 469 g_gate_log(LOG_DEBUG, "Sent %d bytes " 470 "(offset=%ju, size=%zu).", data, 471 (uintmax_t)hdr.gh_offset, 472 (size_t)hdr.gh_length); 473 } 474 } else /* if (hdr.gh_cmd == BIO_WRITE) */ { 475 g_gate_log(LOG_DEBUG, "Waiting for %u bytes of data...", 476 hdr.gh_length); 477 data = recv(sfd, buf, hdr.gh_length, MSG_WAITALL); 478 if (data == -1) { 479 g_gate_xlog("Error while receiving data: %s.", 480 strerror(errno)); 481 } 482 if (pwrite(fd, buf, hdr.gh_length, hdr.gh_offset) == -1) { 483 error = errno; 484 g_gate_log(LOG_ERR, "Error while writing data " 485 "(offset=%llu, size=%u): %s.", 486 hdr.gh_offset, hdr.gh_length, 487 strerror(error)); 488 } else { 489 error = 0; 490 } 491 hdr.gh_error = error; 492 g_gate_swap2n_hdr(&hdr); 493 if (send(sfd, &hdr, sizeof(hdr), 0) == -1) { 494 g_gate_xlog("Error while sending status: %s.", 495 strerror(errno)); 496 } 497 g_gate_swap2h_hdr(&hdr); 498 g_gate_log(LOG_DEBUG, "Received %d bytes (offset=%llu, " 499 "size=%u).", data, hdr.gh_offset, hdr.gh_length); 500 } 501 g_gate_log(LOG_DEBUG, "Tick."); 502 } 503 } 504 505 static void 506 huphandler(int sig __unused) 507 { 508 509 got_sighup = 1; 510 } 511 512 int 513 main(int argc, char *argv[]) 514 { 515 struct sockaddr_in serv; 516 struct sockaddr from; 517 in_addr_t bindaddr; 518 socklen_t fromlen; 519 struct timeval tv; 520 int on, sfd, tmpsfd; 521 pid_t childpid; 522 unsigned bsize, port; 523 524 bindaddr = htonl(INADDR_ANY); 525 port = G_GATE_PORT; 526 for (;;) { 527 int ch; 528 529 ch = getopt(argc, argv, "a:hnp:R:S:v"); 530 if (ch == -1) 531 break; 532 switch (ch) { 533 case 'a': 534 bindaddr = g_gate_str2ip(optarg); 535 if (bindaddr == INADDR_NONE) { 536 errx(EXIT_FAILURE, 537 "Invalid IP/host name to bind to."); 538 } 539 break; 540 case 'n': 541 nagle = 0; 542 break; 543 case 'p': 544 errno = 0; 545 port = strtoul(optarg, NULL, 10); 546 if (port == 0 && errno != 0) 547 errx(EXIT_FAILURE, "Invalid port."); 548 break; 549 case 'R': 550 errno = 0; 551 rcvbuf = strtoul(optarg, NULL, 10); 552 if (rcvbuf == 0 && errno != 0) 553 errx(EXIT_FAILURE, "Invalid rcvbuf."); 554 break; 555 case 'S': 556 errno = 0; 557 sndbuf = strtoul(optarg, NULL, 10); 558 if (sndbuf == 0 && errno != 0) 559 errx(EXIT_FAILURE, "Invalid sndbuf."); 560 break; 561 case 'v': 562 g_gate_verbose++; 563 break; 564 case 'h': 565 default: 566 usage(); 567 } 568 } 569 argc -= optind; 570 argv += optind; 571 572 if (argv[0] != NULL) 573 exports = argv[0]; 574 exports_get(); 575 576 if (!g_gate_verbose) { 577 /* Run in daemon mode. */ 578 if (daemon(0, 0) < 0) 579 g_gate_xlog("Can't daemonize: %s", strerror(errno)); 580 } 581 582 signal(SIGCHLD, SIG_IGN); 583 584 sfd = socket(AF_INET, SOCK_STREAM, 0); 585 if (sfd < 0) 586 g_gate_xlog("Can't open stream socket: %s.", strerror(errno)); 587 bzero(&serv, sizeof(serv)); 588 serv.sin_family = AF_INET; 589 serv.sin_addr.s_addr = bindaddr; 590 serv.sin_port = htons(port); 591 on = 1; 592 if (nagle) { 593 if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &on, 594 sizeof(on)) < 0) { 595 g_gate_xlog("setsockopt() error: %s.", strerror(errno)); 596 } 597 } 598 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 599 g_gate_xlog("setsockopt(): %s.", strerror(errno)); 600 bsize = rcvbuf; 601 if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, &bsize, sizeof(bsize)) < 0) 602 g_gate_xlog("setsockopt(): %s.", strerror(errno)); 603 bsize = sndbuf; 604 if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &bsize, sizeof(bsize)) < 0) 605 g_gate_xlog("setsockopt(): %s.", strerror(errno)); 606 tv.tv_sec = 10; 607 tv.tv_usec = 0; 608 if (setsockopt(sfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) || 609 setsockopt(sfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { 610 g_gate_xlog("setsockopt() error: %s.", strerror(errno)); 611 } 612 if (bind(sfd, (struct sockaddr *)&serv, sizeof(serv)) < 0) 613 g_gate_xlog("bind(): %s.", strerror(errno)); 614 if (listen(sfd, 5) < 0) 615 g_gate_xlog("listen(): %s.", strerror(errno)); 616 617 g_gate_log(LOG_INFO, "Listen on port: %d.", port); 618 619 signal(SIGHUP, huphandler); 620 621 for (;;) { 622 fromlen = sizeof(from); 623 tmpsfd = accept(sfd, &from, &fromlen); 624 if (tmpsfd < 0) 625 g_gate_xlog("accept(): %s.", strerror(errno)); 626 627 if (got_sighup) { 628 got_sighup = 0; 629 exports_get(); 630 } 631 632 if (exports_find(&from, NULL) == NULL) { 633 close(tmpsfd); 634 continue; 635 } 636 637 childpid = fork(); 638 if (childpid < 0) { 639 g_gate_xlog("Cannot create child process: %s.", 640 strerror(errno)); 641 } else if (childpid == 0) { 642 close(sfd); 643 serve(tmpsfd, &from); 644 /* NOTREACHED */ 645 } 646 close(tmpsfd); 647 } 648 close(sfd); 649 exit(EXIT_SUCCESS); 650 } 651