geom_gate userland utility improvements
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 

651 líneas
16 KiB

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