|
@@ -43,16 +43,17 @@
|
43
|
43
|
#include <syslog.h>
|
44
|
44
|
|
45
|
45
|
#ifndef VERSION
|
46
|
|
-#define VERSION "1.3"
|
|
46
|
+#define VERSION "1.4"
|
47
|
47
|
#endif
|
48
|
48
|
|
49
|
49
|
static char *self = NULL;
|
50
|
50
|
|
51
|
|
-static int bind_service (const char *service, int family)
|
|
51
|
+static size_t bind_service (const char *service, int family, int* socks, size_t max_socks)
|
52
|
52
|
{
|
53
|
53
|
struct addrinfo *addr, *it;
|
54
|
54
|
struct addrinfo hints;
|
55
|
55
|
int err, sock, flags;
|
|
56
|
+ size_t count = 0;
|
56
|
57
|
static const int one = 1;
|
57
|
58
|
|
58
|
59
|
memset (&hints, 0, sizeof(hints));
|
|
@@ -62,10 +63,11 @@ static int bind_service (const char *service, int family)
|
62
|
63
|
err = getaddrinfo(NULL, service, &hints, &addr);
|
63
|
64
|
if (err != 0) {
|
64
|
65
|
fprintf(stderr, "%s: bind_service(%s): %s\n", self, service, gai_strerror(err));
|
65
|
|
- return -1;
|
|
66
|
+ return count;
|
66
|
67
|
}
|
67
|
68
|
sock = -1;
|
68
|
69
|
for (it = addr; it; it = it->ai_next) {
|
|
70
|
+ if (max_socks == 0) break;
|
69
|
71
|
sock = socket(it->ai_family, it->ai_socktype, it->ai_protocol);
|
70
|
72
|
if (sock < 0) goto fail;
|
71
|
73
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) goto fail;
|
|
@@ -74,16 +76,18 @@ static int bind_service (const char *service, int family)
|
74
|
76
|
flags = fcntl (sock, F_GETFL, 0);
|
75
|
77
|
if (flags < 0) goto fail;
|
76
|
78
|
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) goto fail;
|
77
|
|
- break;
|
|
79
|
+ *socks++ = sock;
|
|
80
|
+ ++count;
|
|
81
|
+ --max_socks;
|
|
82
|
+ continue;
|
78
|
83
|
fail:
|
79
|
84
|
err = errno;
|
80
|
85
|
if (sock >= 0) close (sock);
|
81
|
|
- sock = -1;
|
82
|
86
|
}
|
83
|
87
|
freeaddrinfo (addr);
|
84
|
|
- if (sock < 0)
|
|
88
|
+ if (count == 0)
|
85
|
89
|
fprintf (stderr, "%s: bind_service(%s): %s\n", self, service, strerror(err));
|
86
|
|
- return sock;
|
|
90
|
+ return count;
|
87
|
91
|
}
|
88
|
92
|
|
89
|
93
|
static int is_hexdigit (char c)
|
|
@@ -237,12 +241,11 @@ typedef void(*handle_t)(srs_t*, FILE*, const char*, const char*, const char**);
|
237
|
241
|
|
238
|
242
|
int main (int argc, char **argv)
|
239
|
243
|
{
|
240
|
|
- int opt, timeout = 1800, family = AF_INET;
|
|
244
|
+ int opt, timeout = 1800, family = AF_UNSPEC;
|
241
|
245
|
int daemonize = FALSE;
|
242
|
246
|
char *forward_service = NULL, *reverse_service = NULL,
|
243
|
247
|
*user = NULL, *domain = NULL, *chroot_dir = NULL;
|
244
|
248
|
char separator = '=';
|
245
|
|
- int forward_sock, reverse_sock;
|
246
|
249
|
char *secret_file = NULL, *pid_file = NULL;
|
247
|
250
|
FILE *pf = NULL, *sf = NULL;
|
248
|
251
|
struct passwd *pwd = NULL;
|
|
@@ -250,10 +253,12 @@ int main (int argc, char **argv)
|
250
|
253
|
char *tmp;
|
251
|
254
|
time_t now;
|
252
|
255
|
srs_t *srs;
|
253
|
|
- struct pollfd fds[3];
|
254
|
256
|
const char **excludes;
|
255
|
257
|
size_t s1 = 0, s2 = 1;
|
256
|
|
- handle_t handler[2] = { handle_forward, handle_reverse };
|
|
258
|
+ struct pollfd fds[4];
|
|
259
|
+ size_t socket_count = 0, sc;
|
|
260
|
+ int sockets[4] = { -1, -1, -1, -1 };
|
|
261
|
+ handle_t handler[4] = { 0, 0, 0, 0 };
|
257
|
262
|
|
258
|
263
|
excludes = (const char**)calloc(1, sizeof(char*));
|
259
|
264
|
tmp = strrchr(argv[0], '/');
|
|
@@ -374,6 +379,8 @@ int main (int argc, char **argv)
|
374
|
379
|
fprintf (stderr, "%s: SRS separator character must be one of '=+-'\n", self);
|
375
|
380
|
return EXIT_FAILURE;
|
376
|
381
|
}
|
|
382
|
+ if (forward_service == NULL) forward_service = strdup("10001");
|
|
383
|
+ if (reverse_service == NULL) reverse_service = strdup("10002");
|
377
|
384
|
|
378
|
385
|
/* The stuff we do first may not be possible from within chroot or without privileges */
|
379
|
386
|
|
|
@@ -397,22 +404,15 @@ int main (int argc, char **argv)
|
397
|
404
|
return EXIT_FAILURE;
|
398
|
405
|
}
|
399
|
406
|
/* Bind ports. May require privileges if the config specifies ports below 1024 */
|
400
|
|
- if (forward_service != NULL) {
|
401
|
|
- forward_sock = bind_service(forward_service, family);
|
402
|
|
- free (forward_service);
|
403
|
|
- } else {
|
404
|
|
- forward_sock = bind_service("10001", family);
|
405
|
|
- }
|
406
|
|
- if (forward_sock < 0) return EXIT_FAILURE;
|
407
|
|
- if (reverse_service != NULL) {
|
408
|
|
- reverse_sock = bind_service(reverse_service, family);
|
409
|
|
- free (reverse_service);
|
410
|
|
- } else {
|
411
|
|
- reverse_sock = bind_service("10002", family);
|
412
|
|
- }
|
413
|
|
- if (reverse_sock < 0) return EXIT_FAILURE;
|
414
|
|
-
|
415
|
|
- /* Open syslog now (NDELAY), because it may no longer reachable from chroot */
|
|
407
|
+ sc = bind_service(forward_service, family, &sockets[socket_count], 4 - socket_count);
|
|
408
|
+ if (sc == 0) return EXIT_FAILURE;
|
|
409
|
+ while (sc-- > 0) handler[socket_count++] = handle_forward;
|
|
410
|
+ free (forward_service);
|
|
411
|
+ sc = bind_service(reverse_service, family, &sockets[socket_count], 4 - socket_count);
|
|
412
|
+ if (sc == 0) return EXIT_FAILURE;
|
|
413
|
+ while (sc-- > 0) handler[socket_count++] = handle_reverse;
|
|
414
|
+ free (reverse_service);
|
|
415
|
+ /* Open syslog now (NDELAY), because it may no longer be reachable from chroot */
|
416
|
416
|
openlog (self, LOG_PID | LOG_NDELAY, LOG_MAIL);
|
417
|
417
|
/* Force loading of timezone info (suggested by patrickdk77) */
|
418
|
418
|
now = time(NULL);
|
|
@@ -470,18 +470,17 @@ int main (int argc, char **argv)
|
470
|
470
|
|
471
|
471
|
srs_set_separator (srs, separator);
|
472
|
472
|
|
473
|
|
- fds[0].fd = forward_sock;
|
474
|
|
- fds[0].events = POLLIN;
|
475
|
|
- fds[1].fd = reverse_sock;
|
476
|
|
- fds[1].events = POLLIN;
|
477
|
|
-
|
|
473
|
+ for (sc = 0; sc < socket_count; ++sc) {
|
|
474
|
+ fds[sc].fd = sockets[sc];
|
|
475
|
+ fds[sc].events = POLLIN;
|
|
476
|
+ }
|
478
|
477
|
while(TRUE) {
|
479
|
|
- int i, conn;
|
|
478
|
+ int conn;
|
480
|
479
|
FILE *fp;
|
481
|
480
|
char linebuf[1024], *line;
|
482
|
481
|
char keybuf[1024], *key;
|
483
|
482
|
|
484
|
|
- if (poll(fds, 2, 1000) < 0) {
|
|
483
|
+ if (poll(fds, socket_count, 1000) < 0) {
|
485
|
484
|
if (errno == EINTR)
|
486
|
485
|
continue;
|
487
|
486
|
if (daemonize)
|
|
@@ -490,20 +489,20 @@ int main (int argc, char **argv)
|
490
|
489
|
fprintf (stderr, "%s: Poll failure: %s\n", self, strerror(errno));
|
491
|
490
|
return EXIT_FAILURE;
|
492
|
491
|
}
|
493
|
|
- for (i = 0; i < 2; ++i) {
|
494
|
|
- if (fds[i].revents) {
|
495
|
|
- conn = accept(fds[i].fd, NULL, NULL);
|
|
492
|
+ for (sc = 0; sc < socket_count; ++sc) {
|
|
493
|
+ if (fds[sc].revents) {
|
|
494
|
+ conn = accept(fds[sc].fd, NULL, NULL);
|
496
|
495
|
if (conn < 0) continue;
|
497
|
496
|
if (fork() == 0) {
|
|
497
|
+ int i;
|
498
|
498
|
// close listen sockets so that we don't stop the main daemon process from restarting
|
499
|
|
- close(forward_sock);
|
500
|
|
- close(reverse_sock);
|
|
499
|
+ for (i = 0; i < socket_count; ++i) close (sockets[i]);
|
501
|
500
|
|
502
|
501
|
fp = fdopen(conn, "r+");
|
503
|
502
|
if (fp == NULL) exit(EXIT_FAILURE);
|
504
|
|
- fds[2].fd = conn;
|
505
|
|
- fds[2].events = POLLIN;
|
506
|
|
- if (poll(&fds[2], 1, timeout * 1000) <= 0) return EXIT_FAILURE;
|
|
503
|
+ fds[0].fd = conn;
|
|
504
|
+ fds[0].events = POLLIN;
|
|
505
|
+ if (poll(fds, 1, timeout * 1000) <= 0) return EXIT_FAILURE;
|
507
|
506
|
line = fgets(linebuf, sizeof(linebuf), fp);
|
508
|
507
|
while (line) {
|
509
|
508
|
fseek (fp, 0, SEEK_CUR); /* Workaround for Solaris */
|
|
@@ -522,9 +521,9 @@ int main (int argc, char **argv)
|
522
|
521
|
}
|
523
|
522
|
key = url_decode(keybuf, sizeof(keybuf), token);
|
524
|
523
|
if (!key) break;
|
525
|
|
- handler[i](srs, fp, key, domain, excludes);
|
|
524
|
+ handler[sc](srs, fp, key, domain, excludes);
|
526
|
525
|
fflush (fp);
|
527
|
|
- if (poll(&fds[2], 1, timeout * 1000) <= 0) break;
|
|
526
|
+ if (poll(fds, 1, timeout * 1000) <= 0) break;
|
528
|
527
|
line = fgets(linebuf, sizeof(linebuf), fp);
|
529
|
528
|
}
|
530
|
529
|
fclose (fp);
|