chiark / gitweb /
Fix trailing whitespace.
[preload-hacks] / noip.c
CommitLineData
e4976bb0 1#define _GNU_SOURCE
2#undef sun
3#undef SUN
4#define DEBUG
5
6#include <ctype.h>
7#include <errno.h>
8#include <stdio.h>
9#include <stdlib.h>
10
11#include <unistd.h>
12#include <dirent.h>
13#include <dlfcn.h>
14#include <fcntl.h>
15#include <pwd.h>
16
17#include <sys/ioctl.h>
18#include <sys/socket.h>
19#include <sys/stat.h>
20#include <sys/un.h>
21
22#include <netinet/in.h>
23#include <arpa/inet.h>
24#include <netinet/tcp.h>
25#include <netinet/udp.h>
26#include <net/if.h>
27
28enum { UNUSED, STALE, USED };
29enum { WANT_FRESH, WANT_EXISTING };
30enum { DENY, ALLOW };
31typedef struct aclnode {
32 struct aclnode *next;
33 int act;
34 unsigned long minaddr, maxaddr;
35 unsigned short minport, maxport;
36} aclnode;
37
38#define MAX_LOCAL_IPADDRS 16
39static struct in_addr local_ipaddrs[MAX_LOCAL_IPADDRS];
40static int n_local_ipaddrs;
41
42static uid_t uid;
43static char *sockdir = 0;
44static int debug = 0;
f6049fdd 45static unsigned minautoport = 16384, maxautoport = 65536;
e4976bb0 46
47static aclnode *bind_real, **bind_tail = &bind_real;
48static aclnode *connect_real, **connect_tail = &connect_real;
49
50/* --- Import magic --- */
51
52#define IMPORTS(_) \
53 _(socket, int, (int, int, int)) \
54 _(socketpair, int, (int, int, int, int *)) \
55 _(connect, int, (int, const struct sockaddr *, socklen_t)) \
56 _(bind, int, (int, const struct sockaddr *, socklen_t)) \
57 _(accept, int, (int, struct sockaddr *, socklen_t *)) \
58 _(getsockname, int, (int, struct sockaddr *, socklen_t *)) \
59 _(getpeername, int, (int, struct sockaddr *, socklen_t *)) \
60 _(getsockopt, int, (int, int, int, void *, socklen_t *)) \
61 _(setsockopt, int, (int, int, int, const void *, socklen_t)) \
62 _(sendto, ssize_t, (int, const void *buf, size_t, int, \
63 const struct sockaddr *to, socklen_t tolen)) \
64 _(recvfrom, ssize_t, (int, void *buf, size_t, int, \
65 struct sockaddr *from, socklen_t *fromlen)) \
66 _(sendmsg, ssize_t, (int, const struct msghdr *, int)) \
67 _(recvmsg, ssize_t, (int, struct msghdr *, int)) \
68 _(close, int, (int))
69
70#define DECL(imp, ret, args) static ret (*real_##imp) args;
71IMPORTS(DECL)
72#undef DECL
73
74static void setup(void) __attribute__((constructor));
75static void import(void)
76{
77#define IMPORT(imp, ret, args) \
78 real_##imp = (ret (*)args)dlsym(RTLD_NEXT, #imp);
79 IMPORTS(IMPORT)
80#undef IMPORT
81}
82
83/* --- Support --- */
84
85#define SA(sa) ((struct sockaddr *)(sa))
86#define SIN(sa) ((struct sockaddr_in *)(sa))
87#define SUN(sa) ((struct sockaddr_un *)(sa))
88
89#define UC(ch) ((unsigned char)(ch))
90
91#define NEW(x) ((x) = xmalloc(sizeof(*x)))
92#define NEWV(x, n) ((x) = xmalloc(sizeof(*x) * (n)))
93
94#ifdef DEBUG
95# define D(body) { if (debug) { body } }
96#else
97# define D(body) ;
98#endif
99
100#define PRESERVING_ERRNO(body) do { \
101 int _err = errno; { body } errno = _err; \
102} while (0)
103
104static void *xmalloc(size_t n)
105{
106 void *p;
107 if (!n) return (0);
3ef1fec9 108 if ((p = malloc(n)) == 0) { perror("malloc"); exit(127); }
e4976bb0 109 return (p);
110}
111
112static char *xstrdup(const char *p)
113{
114 size_t n = strlen(p) + 1;
115 char *q = xmalloc(n);
116 memcpy(q, p, n);
117 return (q);
118}
119
3ef1fec9 120static int unix_socket_status(struct sockaddr_un *sun, int quickp)
e4976bb0 121{
122 struct stat st;
123 FILE *fp = 0;
124 size_t len, n;
125 int rc;
126 char buf[256];
127
3ef1fec9 128 if (stat(sun->sun_path, &st))
129 return (errno == ENOENT ? UNUSED : USED);
4ab301de 130 if (!S_ISSOCK(st.st_mode) || quickp)
3ef1fec9 131 return (USED);
e4976bb0 132 rc = USED;
e4976bb0 133 if ((fp = fopen("/proc/net/unix", "r")) == 0)
134 goto done;
135 fgets(buf, sizeof(buf), fp); /* skip header */
136 len = strlen(sun->sun_path);
137 while (fgets(buf, sizeof(buf), fp)) {
138 n = strlen(buf);
139 if (n >= len + 2 && buf[n - len - 2] == ' ' && buf[n - 1] == '\n' &&
140 memcmp(buf + n - len - 1, sun->sun_path, len) == 0)
141 goto done;
142 }
143 if (ferror(fp))
144 goto done;
145 rc = STALE;
146done:
147 if (fp) fclose(fp);
148 return (rc);
149}
150
151#ifdef DEBUG
152
153static void dump_aclnode(aclnode *a)
154{
155 char minbuf[16], maxbuf[16];
156 struct in_addr amin, amax;
157
158 amin.s_addr = htonl(a->minaddr);
159 amax.s_addr = htonl(a->maxaddr);
160 fprintf(stderr, "noip: %c ", a->act ? '+' : '-');
161 if (a->minaddr == 0 && a->maxaddr == 0xffffffff)
162 fprintf(stderr, "any");
163 else {
164 fprintf(stderr, "%s",
165 inet_ntop(AF_INET, &amin, minbuf, sizeof(minbuf)));
166 if (a->maxaddr != a->minaddr) {
167 fprintf(stderr, "-%s",
168 inet_ntop(AF_INET, &amax, maxbuf, sizeof(maxbuf)));
169 }
170 }
171 if (a->minport != 0 || a->maxport != 0xffff) {
172 fprintf(stderr, ":%u", (unsigned)a->minport);
173 if (a->minport != a->maxport)
174 fprintf(stderr, "-%u", (unsigned)a->maxport);
175 }
176 fputc('\n', stderr);
177}
178
179#endif
180
181static int acl_allows_p(aclnode *a, const struct sockaddr_in *sin)
182{
183 unsigned long addr = ntohl(sin->sin_addr.s_addr);
184 unsigned short port = ntohs(sin->sin_port);
185 int act = ALLOW;
186
187 D( char buf[16];
188 fprintf(stderr, "noip: check %s:%u\n",
189 inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)),
190 ntohs((unsigned)sin->sin_port)); )
191 for (; a; a = a->next) {
192 D( dump_aclnode(a); )
193 if (a->minaddr <= addr && addr <= a->maxaddr &&
194 a->minport <= port && port <= a->maxport) {
195 D( fprintf(stderr, "noip: aha! %s\n", a->act ? "ALLOW" : "DENY"); )
196 return (a->act);
197 }
198 act = a->act;
199 }
200 D( fprintf(stderr, "noip: nothing found: %s\n", act ? "DENY" : "ALLOW"); )
201 return (!act);
202}
203
204#ifdef DEBUG
205
206static void dump_acl(aclnode *a)
207{
208 int act = ALLOW;
9f82ba1f 209
e4976bb0 210 for (; a; a = a->next) {
211 dump_aclnode(a);
212 act = a->act;
213 }
214 fprintf(stderr, "noip: [default policy: %s]\n",
215 act == ALLOW ? "DENY" : "ALLOW");
216}
217
218#endif
219
f6049fdd 220static unsigned randrange(unsigned min, unsigned max)
221{
222 unsigned mask, i;
223
224 /* It's so nice not to have to care about the quality of the generator
225 much! */
226 max -= min;
227 for (mask = 1; mask < max; mask = (mask << 1) | 1)
228 ;
229 do i = rand() & mask; while (i > max);
230 return (i + min);
231}
232
e4976bb0 233static int encode_inet_addr(struct sockaddr_un *sun,
234 const struct sockaddr_in *sin,
235 int want)
236{
237 int i;
3ef1fec9 238 int desperatep = 0;
e4976bb0 239 char buf[INET_ADDRSTRLEN];
240 int rc;
241
242 D( fprintf(stderr, "noip: encode %s:%u (%s)",
243 inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)),
244 (unsigned)ntohs(sin->sin_port),
245 want == WANT_EXISTING ? "EXISTING" : "FRESH"); )
246 sun->sun_family = AF_UNIX;
247 if (sin->sin_port || want == WANT_EXISTING) {
248 snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s:%u", sockdir,
249 inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)),
250 (unsigned)ntohs(sin->sin_port));
251 rc = unix_socket_status(sun, 0);
252 if (rc == STALE) unlink(sun->sun_path);
253 if (rc != USED && want == WANT_EXISTING) {
254 snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/0.0.0.0:%u",
255 sockdir, (unsigned)ntohs(sin->sin_port));
256 if (unix_socket_status(sun, 0) == STALE) unlink(sun->sun_path);
257 }
258 } else {
f6049fdd 259 for (i = 0; i < 10; i++) {
260 snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s:%u", sockdir,
261 inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)),
262 randrange(minautoport, maxautoport));
263 if (unix_socket_status(sun, 1) == UNUSED) goto found;
264 }
3ef1fec9 265 for (desperatep = 0; desperatep < 2; desperatep++) {
f6049fdd 266 for (i = minautoport; i <= maxautoport; i++) {
e4976bb0 267 snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s:%u", sockdir,
268 inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)),
269 (unsigned)i);
3ef1fec9 270 rc = unix_socket_status(sun, !desperatep);
e4976bb0 271 switch (rc) {
272 case STALE: unlink(sun->sun_path);
273 case UNUSED: goto found;
274 }
275 }
276 }
277 errno = EADDRINUSE;
278 D( fprintf(stderr, " -- can't resolve\n"); )
279 return (-1);
280 found:;
281 }
282 D( fprintf(stderr, " -> `%s'\n", sun->sun_path); )
283 return (0);
284}
285
286static int decode_inet_addr(struct sockaddr_in *sin,
287 const struct sockaddr_un *sun,
288 socklen_t len)
289{
290 char buf[INET_ADDRSTRLEN + 16];
291 char *p;
292 size_t n = strlen(sockdir), nn = strlen(sun->sun_path);
293 struct sockaddr_in sin_mine;
294 unsigned long port;
295
296 if (!sin)
297 sin = &sin_mine;
298 if (sun->sun_family != AF_UNIX)
299 return (-1);
300 if (len < sizeof(sun)) ((char *)sun)[len] = 0;
301 D( fprintf(stderr, "noip: decode (%d) `%s'",
302 *sun->sun_path, sun->sun_path); )
303 if (!sun->sun_path[0]) {
304 sin->sin_family = AF_INET;
305 sin->sin_addr.s_addr = INADDR_ANY;
306 sin->sin_port = 0;
307 D( fprintf(stderr, " -- unbound socket\n"); )
308 return (0);
309 }
310 if (nn < n + 1 || nn - n >= sizeof(buf) || sun->sun_path[n] != '/' ||
311 memcmp(sun->sun_path, sockdir, n) != 0) {
312 D( fprintf(stderr, " -- not one of ours\n"); )
313 return (-1);
314 }
315 memcpy(buf, sun->sun_path + n + 1, nn - n);
316 if ((p = strchr(buf, ':')) == 0) {
317 D( fprintf(stderr, " -- malformed (no port)\n"); )
318 return (-1);
319 }
320 *p++ = 0;
321 sin->sin_family = AF_INET;
322 if (inet_pton(AF_INET, buf, &sin->sin_addr) <= 0) {
323 D( fprintf(stderr, " -- malformed (bad address `%s')\n", buf); )
324 return (-1);
325 }
326 port = strtoul(p, &p, 10);
327 if (*p || port >= 65536) {
328 D( fprintf(stderr, " -- malformed (port out of range)"); )
329 return (-1);
330 }
331 sin->sin_port = htons(port);
332 D( fprintf(stderr, " -> %s:%u\n",
333 inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)),
334 (unsigned)port); )
335 return (0);
336}
337
338static int fixup_real_ip_socket(int sk)
339{
340 int nsk;
341 int type;
342 int f, fd;
343 struct sockaddr_un sun;
344 struct sockaddr_in sin;
345 socklen_t len;
346
347#define OPTS(_) \
348 _(DEBUG, int) \
349 _(REUSEADDR, int) \
350 _(DONTROUTE, int) \
351 _(BROADCAST, int) \
352 _(SNDBUF, int) \
353 _(RCVBUF, int) \
354 _(OOBINLINE, int) \
355 _(NO_CHECK, int) \
356 _(LINGER, struct linger) \
357 _(BSDCOMPAT, int) \
358 _(RCVLOWAT, int) \
359 _(RCVTIMEO, struct timeval) \
360 _(SNDTIMEO, struct timeval)
361
362 len = sizeof(sun);
363 if (real_getsockname(sk, SA(&sun), &len))
364 return (-1);
365 if (decode_inet_addr(&sin, &sun, len))
366 return (0); /* Not one of ours */
367 len = sizeof(type);
368 if (real_getsockopt(sk, SOL_SOCKET, SO_TYPE, &type, &len) < 0 ||
369 (nsk = real_socket(PF_INET, type, 0)) < 0)
370 return (-1);
371#define FIX(opt, ty) do { \
372 ty ov_; \
373 len = sizeof(ov_); \
374 if (real_getsockopt(sk, SOL_SOCKET, SO_##opt, &ov_, &len) < 0 || \
375 real_setsockopt(nsk, SOL_SOCKET, SO_##opt, &ov_, len)) { \
376 real_close(nsk); \
377 return (-1); \
378 } \
379} while (0);
380 OPTS(FIX)
381#undef FIX
382 if ((f = fcntl(sk, F_GETFL)) < 0 ||
383 (fd = fcntl(sk, F_GETFD)) < 0 ||
384 fcntl(nsk, F_SETFL, f) < 0 ||
385 dup2(nsk, sk) < 0) {
386 real_close(nsk);
387 return (-1);
388 }
389 unlink(sun.sun_path);
390 real_close(nsk);
391 if (fcntl(sk, F_SETFD, fd) < 0) {
392 perror("noip: fixup_real_ip_socket F_SETFD");
393 abort();
394 }
395 return (0);
396}
397
398static int do_implicit_bind(int sk, const struct sockaddr **sa,
399 socklen_t *len, struct sockaddr_un *sun)
400{
401 struct sockaddr_in sin;
402 socklen_t mylen = sizeof(*sun);
403
404 if (acl_allows_p(connect_real, SIN(*sa))) {
405 if (fixup_real_ip_socket(sk))
406 return (-1);
407 } else {
408 if (real_getsockname(sk, SA(sun), &mylen) < 0)
409 return (-1);
410 if (sun->sun_family == AF_UNIX) {
411 if (mylen < sizeof(*sun)) ((char *)sun)[mylen] = 0;
412 if (!sun->sun_path[0]) {
413 sin.sin_family = AF_INET;
4ab301de 414 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
e4976bb0 415 sin.sin_port = 0;
416 encode_inet_addr(sun, &sin, WANT_FRESH);
417 if (real_bind(sk, SA(sun), SUN_LEN(sun)))
418 return (-1);
419 }
420 encode_inet_addr(sun, SIN(*sa), WANT_EXISTING);
421 *sa = SA(sun);
422 *len = SUN_LEN(sun);
423 }
424 }
425 return (0);
426}
427
428static void return_fake_name(struct sockaddr *sa, socklen_t len,
429 struct sockaddr *fake, socklen_t *fakelen)
430{
431 struct sockaddr_in sin;
432 socklen_t alen;
433
434 if (sa->sa_family == AF_UNIX && !decode_inet_addr(&sin, SUN(sa), len)) {
435 sa = SA(&sin);
436 len = sizeof(sin);
437 }
438 alen = len;
439 if (len > *fakelen)
440 len = *fakelen;
441 if (len > 0)
442 memcpy(fake, sa, len);
443 *fakelen = alen;
444}
445
446/* --- Configuration --- */
447
448static char *home(void)
449{
450 char *p;
451 struct passwd *pw;
452
3ef1fec9 453 if (getuid() == uid &&
454 (p = getenv("HOME")) != 0)
455 return (p);
456 else if ((pw = getpwuid(uid)) != 0)
457 return (pw->pw_dir);
458 else
459 return "/notexist";
e4976bb0 460}
461
462static char *tmpdir(void)
463{
464 char *p;
465
466 if ((p = getenv("TMPDIR")) != 0) return (p);
467 else if ((p = getenv("TMP")) != 0) return (p);
468 else return ("/tmp");
469}
470
471static char *user(void)
472{
473 static char buf[16];
474 char *p;
475 struct passwd *pw;
476
477 if ((p = getenv("USER")) != 0) return (p);
478 else if ((p = getenv("LOGNAME")) != 0) return (p);
479 else if ((pw = getpwuid(uid)) != 0) return (pw->pw_name);
480 else {
481 snprintf(buf, sizeof(buf), "uid-%lu", (unsigned long)uid);
482 return (buf);
483 }
484}
485
486#define SKIPSPC do { while (*p && isspace(UC(*p))) p++; } while (0)
487#define NEXTWORD(q) do { \
488 SKIPSPC; \
489 q = p; \
490 while (*p && !isspace(UC(*p))) p++; \
491 if (*p) *p++ = 0; \
492} while (0)
493#define NEXTADDR(q, del) do { \
494 SKIPSPC; \
495 q = p; \
496 while (*p && (*p == '.' || isdigit(UC(*p)))) p++; \
497 del = *p; \
498 if (*p) *p++ = 0; \
499} while (0)
500#define NEXTNUMBER(q, del) do { \
501 SKIPSPC; \
502 q = p; \
503 while (*p && isdigit(UC(*p))) p++; \
504 del = *p; \
505 if (*p) *p++ = 0; \
506} while (0)
507#define RESCAN(del) do { if (del) *--p = del; } while (0)
508#define KWMATCHP(kw) (strncmp(p, kw, sizeof(kw) - 1) == 0 && \
509 !isalnum(UC(p[sizeof(kw) - 1])) && \
510 (p += sizeof(kw) - 1))
9f82ba1f 511
e4976bb0 512static void parse_ports(char **pp, unsigned short *min, unsigned short *max)
513{
514 char *p = *pp, *q;
515 int del;
516
517 SKIPSPC;
f6049fdd 518 if (*p != ':')
519 { *min = 0; *max = 0xffff; }
520 else {
e4976bb0 521 p++;
f6049fdd 522 NEXTNUMBER(q, del); *min = strtoul(q, 0, 0); RESCAN(del);
e4976bb0 523 SKIPSPC;
f6049fdd 524 if (*p == '-')
d83beb5c 525 { p++; NEXTNUMBER(q, del); *max = strtoul(q, 0, 0); RESCAN(del); }
f6049fdd 526 else
e4976bb0 527 *max = *min;
528 }
529 *pp = p;
530}
531
532#define ACLNODE(tail_, act_, \
533 minaddr_, maxaddr_, minport_, maxport_) do { \
534 aclnode *a_; \
535 NEW(a_); \
536 a_->act = act_; \
537 a_->minaddr = minaddr_; a_->maxaddr = maxaddr_; \
538 a_->minport = minport_; a_->maxport = maxport_; \
539 *tail_ = a_; tail_ = &a_->next; \
540} while (0)
541
542static void parse_acl_line(char **pp, aclnode ***tail)
543{
544 struct in_addr addr;
545 unsigned long minaddr, maxaddr, mask;
546 unsigned short minport, maxport;
547 int i, n;
548 int act;
549 int del;
550 char *p = *pp;
551 char *q;
552
a6d9626b 553 for (;;) {
554 SKIPSPC;
555 if (*p == '+') act = ALLOW;
556 else if (*p == '-') act = DENY;
557 else goto bad;
e4976bb0 558
a6d9626b 559 p++;
560 SKIPSPC;
561 if (KWMATCHP("any")) {
e4976bb0 562 minaddr = 0;
563 maxaddr = 0xffffffff;
a6d9626b 564 goto justone;
565 } else if (KWMATCHP("local")) {
566 parse_ports(&p, &minport, &maxport);
567 ACLNODE(*tail, act, 0, 0, minport, maxport);
568 ACLNODE(*tail, act, 0xffffffff, 0xffffffff, minport, maxport);
569 for (i = 0; i < n_local_ipaddrs; i++) {
570 minaddr = ntohl(local_ipaddrs[i].s_addr);
571 ACLNODE(*tail, act, minaddr, minaddr, minport, maxport);
572 }
e4976bb0 573 } else {
a6d9626b 574 if (*p == ':') {
575 minaddr = 0;
576 maxaddr = 0xffffffff;
577 } else {
e4976bb0 578 NEXTADDR(q, del);
579 if (inet_pton(AF_INET, q, &addr) <= 0) goto bad;
a6d9626b 580 minaddr = ntohl(addr.s_addr);
e4976bb0 581 RESCAN(del);
a6d9626b 582 SKIPSPC;
583 if (*p == '-') {
584 p++;
585 NEXTADDR(q, del);
e4976bb0 586 if (inet_pton(AF_INET, q, &addr) <= 0) goto bad;
a6d9626b 587 RESCAN(del);
588 maxaddr = ntohl(addr.s_addr);
589 } else if (*p == '/') {
590 p++;
591 NEXTADDR(q, del);
592 if (strchr(q, '.')) {
593 if (inet_pton(AF_INET, q, &addr) <= 0) goto bad;
594 mask = ntohl(addr.s_addr);
595 } else {
f6049fdd 596 n = strtoul(q, 0, 0);
a6d9626b 597 mask = (~0ul << (32 - n)) & 0xffffffff;
598 }
599 RESCAN(del);
600 minaddr &= mask;
601 maxaddr = minaddr | (mask ^ 0xffffffff);
602 } else
603 maxaddr = minaddr;
604 }
605 justone:
606 parse_ports(&p, &minport, &maxport);
607 ACLNODE(*tail, act, minaddr, maxaddr, minport, maxport);
e4976bb0 608 }
a6d9626b 609 SKIPSPC;
610 if (*p != ',') break;
611 p++;
e4976bb0 612 }
613 return;
614
615bad:
616 D( fprintf(stderr, "noip: bad acl spec (ignored)\n"); )
617 return;
618}
619
f6049fdd 620static void parse_autoports(char **pp)
621{
622 char *p = *pp, *q;
623 unsigned x, y;
624 int del;
625
626 SKIPSPC;
627 NEXTNUMBER(q, del); x = strtoul(q, 0, 0); RESCAN(del);
628 SKIPSPC;
629 if (*p != '-') goto bad; p++;
630 NEXTNUMBER(q, del); y = strtoul(q, 0, 0); RESCAN(del);
631 minautoport = x; maxautoport = y;
632 return;
633
634bad:
635 D( fprintf(stderr, "bad port range (ignored)\n"); )
636 return;
637}
638
a6d9626b 639static void parse_acl_env(const char *var, aclnode ***tail)
640{
f6049fdd 641 char *p, *q;
a6d9626b 642
643 if ((p = getenv(var)) != 0) {
f6049fdd 644 p = q = xstrdup(p);
645 parse_acl_line(&q, tail);
a6d9626b 646 free(p);
647 }
648}
649
e4976bb0 650static void readconfig(void)
651{
652 FILE *fp;
653 char buf[1024];
654 size_t n;
f6049fdd 655 char *p, *q, *cmd;
e4976bb0 656
a6d9626b 657 parse_acl_env("NOIP_REALBIND_BEFORE", &bind_tail);
658 parse_acl_env("NOIP_REALCONNECT_BEFORE", &connect_tail);
f6049fdd 659 if ((p = getenv("NOIP_AUTOPORTS")) != 0) {
660 p = q = xstrdup(p);
661 parse_autoports(&q);
662 free(p);
663 }
4ab301de 664 if ((p = getenv("NOIP_CONFIG")) == 0)
665 snprintf(p = buf, sizeof(buf), "%s/.noip", home());
666 D( fprintf(stderr, "noip: config file: %s\n", p); )
667
668 if ((fp = fopen(p, "r")) == 0) {
669 D( fprintf(stderr, "noip: couldn't read config: %s\n",
670 strerror(errno)); )
f6049fdd 671 goto done;
4ab301de 672 }
e4976bb0 673 while (fgets(buf, sizeof(buf), fp)) {
674 n = strlen(buf);
675 p = buf;
676
677 SKIPSPC;
678 if (!*p || *p == '#') continue;
679 while (n && isspace(UC(buf[n - 1]))) n--;
680 buf[n] = 0;
681 NEXTWORD(cmd);
682 SKIPSPC;
683
684 if (strcmp(cmd, "socketdir") == 0)
685 sockdir = xstrdup(p);
686 else if (strcmp(cmd, "realbind") == 0)
687 parse_acl_line(&p, &bind_tail);
688 else if (strcmp(cmd, "realconnect") == 0)
689 parse_acl_line(&p, &connect_tail);
f6049fdd 690 else if (strcmp(cmd, "autoports") == 0)
691 parse_autoports(&p);
e4976bb0 692 else if (strcmp(cmd, "debug") == 0)
693 debug = *p ? atoi(p) : 1;
694 else
695 D( fprintf(stderr, "noip: bad config command %s\n", cmd); )
696 }
697 fclose(fp);
698
699done:
a6d9626b 700 parse_acl_env("NOIP_REALBIND", &bind_tail);
701 parse_acl_env("NOIP_REALCONNECT", &connect_tail);
702 parse_acl_env("NOIP_REALBIND_AFTER", &bind_tail);
703 parse_acl_env("NOIP_REALCONNECT_AFTER", &connect_tail);
e4976bb0 704 *bind_tail = 0;
705 *connect_tail = 0;
a6d9626b 706 if (!sockdir) sockdir = getenv("NOIP_SOCKETDIR");
e4976bb0 707 if (!sockdir) {
708 snprintf(buf, sizeof(buf), "%s/noip-%s", tmpdir(), user());
709 sockdir = xstrdup(buf);
710 }
3ef1fec9 711 D( fprintf(stderr, "noip: socketdir: %s\n", sockdir);
f6049fdd 712 fprintf(stderr, "noip: autoports: %u-%u\n",
713 minautoport, maxautoport);
e4976bb0 714 fprintf(stderr, "noip: realbind acl:\n");
715 dump_acl(bind_real);
716 fprintf(stderr, "noip: realconnect acl:\n");
717 dump_acl(connect_real); )
718}
719
720/* --- Hooks --- */
721
722int socket(int pf, int ty, int proto)
723{
724 if (pf == PF_INET) {
725 pf = PF_UNIX;
726 proto = 0;
727 }
728 return real_socket(pf, ty, proto);
729}
730
731int socketpair(int pf, int ty, int proto, int *sk)
732{
733 if (pf == PF_INET) {
734 pf = PF_UNIX;
735 proto = 0;
736 }
737 return (real_socketpair(pf, ty, proto, sk));
738}
739
740int bind(int sk, const struct sockaddr *sa, socklen_t len)
741{
742 struct sockaddr_un sun;
743
9f82ba1f 744 if (sa->sa_family == AF_INET) {
e4976bb0 745 PRESERVING_ERRNO({
746 if (acl_allows_p(bind_real, SIN(sa))) {
747 if (fixup_real_ip_socket(sk))
748 return (-1);
749 } else {
750 encode_inet_addr(&sun, SIN(sa), WANT_FRESH);
751 sa = SA(&sun);
752 len = SUN_LEN(&sun);
753 }
754 });
755 }
756 return real_bind(sk, sa, len);
757}
758
759int connect(int sk, const struct sockaddr *sa, socklen_t len)
760{
761 struct sockaddr_un sun;
762
763 if (sa->sa_family == AF_INET) {
764 PRESERVING_ERRNO({
765 do_implicit_bind(sk, &sa, &len, &sun);
766 });
767 }
768 return real_connect(sk, sa, len);
769}
770
771ssize_t sendto(int sk, const void *buf, size_t len, int flags,
772 const struct sockaddr *to, socklen_t tolen)
773{
774 struct sockaddr_un sun;
775
776 if (to && to->sa_family == AF_INET) {
777 PRESERVING_ERRNO({
778 do_implicit_bind(sk, &to, &tolen, &sun);
779 });
780 }
781 return real_sendto(sk, buf, len, flags, to, tolen);
782}
783
784ssize_t recvfrom(int sk, void *buf, size_t len, int flags,
785 struct sockaddr *from, socklen_t *fromlen)
786{
787 char sabuf[1024];
788 socklen_t mylen = sizeof(sabuf);
789 ssize_t n;
790
791 if (!from)
792 return real_recvfrom(sk, buf, len, flags, 0, 0);
793 PRESERVING_ERRNO({
794 n = real_recvfrom(sk, buf, len, flags, SA(sabuf), &mylen);
795 if (n < 0)
796 return (-1);
797 return_fake_name(SA(sabuf), mylen, from, fromlen);
798 });
799 return (n);
800}
801
802ssize_t sendmsg(int sk, const struct msghdr *msg, int flags)
803{
804 struct sockaddr_un sun;
805 const struct sockaddr *sa;
806 struct msghdr mymsg;
807
808 if (msg->msg_name && SA(msg->msg_name)->sa_family == AF_INET) {
809 PRESERVING_ERRNO({
810 sa = SA(msg->msg_name);
811 mymsg = *msg;
812 do_implicit_bind(sk, &sa, &mymsg.msg_namelen, &sun);
813 mymsg.msg_name = SA(sa);
814 msg = &mymsg;
815 });
816 }
817 return real_sendmsg(sk, msg, flags);
818}
819
820ssize_t recvmsg(int sk, struct msghdr *msg, int flags)
821{
822 char sabuf[1024];
823 struct sockaddr *sa;
824 socklen_t len;
825 ssize_t n;
826
827 if (!msg->msg_name)
828 return real_recvmsg(sk, msg, flags);
829 PRESERVING_ERRNO({
830 sa = SA(msg->msg_name);
831 len = msg->msg_namelen;
832 msg->msg_name = sabuf;
833 msg->msg_namelen = sizeof(sabuf);
834 n = real_recvmsg(sk, msg, flags);
835 if (n < 0)
836 return (-1);
837 return_fake_name(SA(sabuf), msg->msg_namelen, sa, &len);
838 msg->msg_name = sa;
839 msg->msg_namelen = len;
840 });
841 return (n);
842}
843
844int accept(int sk, struct sockaddr *sa, socklen_t *len)
845{
846 char sabuf[1024];
847 socklen_t mylen = sizeof(sabuf);
848 int nsk = real_accept(sk, SA(sabuf), &mylen);
849
850 if (nsk < 0)
851 return (-1);
852 return_fake_name(SA(sabuf), mylen, sa, len);
853 return (nsk);
854}
855
856int getsockname(int sk, struct sockaddr *sa, socklen_t *len)
857{
858 PRESERVING_ERRNO({
859 char sabuf[1024];
860 socklen_t mylen = sizeof(sabuf);
861 if (real_getsockname(sk, SA(sabuf), &mylen))
862 return (-1);
863 return_fake_name(SA(sabuf), mylen, sa, len);
864 });
865 return (0);
866}
867
868int getpeername(int sk, struct sockaddr *sa, socklen_t *len)
869{
870 PRESERVING_ERRNO({
871 char sabuf[1024];
872 socklen_t mylen = sizeof(sabuf);
873 if (real_getpeername(sk, SA(sabuf), &mylen))
874 return (-1);
875 return_fake_name(SA(sabuf), mylen, sa, len);
876 });
877 return (0);
878}
879
880int getsockopt(int sk, int lev, int opt, void *p, socklen_t *len)
881{
882 switch (lev) {
883 case SOL_IP:
884 case SOL_TCP:
885 case SOL_UDP:
886 if (*len > 0)
887 memset(p, 0, *len);
888 return (0);
889 }
890 return real_getsockopt(sk, lev, opt, p, len);
891}
892
893int setsockopt(int sk, int lev, int opt, const void *p, socklen_t len)
894{
895 switch (lev) {
896 case SOL_IP:
897 case SOL_TCP:
898 case SOL_UDP:
899 return (0);
900 }
901 switch (opt) {
902 case SO_BINDTODEVICE:
903 case SO_ATTACH_FILTER:
904 case SO_DETACH_FILTER:
905 return (0);
906 }
907 return real_setsockopt(sk, lev, opt, p, len);
908}
909
910/* --- Initialization --- */
911
912static void cleanup_sockdir(void)
913{
914 DIR *dir;
915 struct dirent *d;
3ef1fec9 916 struct sockaddr_in sin;
e4976bb0 917 struct sockaddr_un sun;
3ef1fec9 918 struct stat st;
e4976bb0 919
920 if ((dir = opendir(sockdir)) == 0)
921 return;
4ab301de 922 sun.sun_family = AF_UNIX;
e4976bb0 923 while ((d = readdir(dir)) != 0) {
924 if (d->d_name[0] == '.') continue;
925 snprintf(sun.sun_path, sizeof(sun.sun_path),
926 "%s/%s", sockdir, d->d_name);
3ef1fec9 927 if (decode_inet_addr(&sin, &sun, SUN_LEN(&sun)) ||
928 stat(sun.sun_path, &st) ||
4ab301de 929 !S_ISSOCK(st.st_mode)) {
930 D( fprintf(stderr, "noip: ignoring unknown socketdir entry `%s'\n",
931 sun.sun_path); )
3ef1fec9 932 continue;
4ab301de 933 }
e4976bb0 934 if (unix_socket_status(&sun, 0) == STALE) {
935 D( fprintf(stderr, "noip: clearing away stale socket %s\n",
936 d->d_name); )
937 unlink(sun.sun_path);
938 }
939 }
940 closedir(dir);
941}
942
943static void get_local_ipaddrs(void)
944{
945 struct if_nameindex *ifn;
946 struct ifreq ifr;
947 int sk;
948 int i;
949
950 ifn = if_nameindex();
951 if ((sk = real_socket(PF_INET, SOCK_STREAM, 00)) < 0)
952 return;
953 for (i = n_local_ipaddrs = 0;
954 n_local_ipaddrs < MAX_LOCAL_IPADDRS &&
955 ifn[i].if_name && *ifn[i].if_name;
956 i++) {
957 strcpy(ifr.ifr_name, ifn[i].if_name);
958 if (ioctl(sk, SIOCGIFADDR, &ifr) || ifr.ifr_addr.sa_family != AF_INET)
959 continue;
960 local_ipaddrs[n_local_ipaddrs++] =
961 SIN(&ifr.ifr_addr)->sin_addr;
962 D( fprintf(stderr, "noip: local addr %s = %s\n", ifn[i].if_name,
963 inet_ntoa(local_ipaddrs[n_local_ipaddrs - 1])); )
964 }
965 close(sk);
966}
967
3ef1fec9 968static void printerr(const char *p) { write(STDERR_FILENO, p, strlen(p)); }
969
970static void create_sockdir(void)
971{
972 struct stat st;
973
974 if (stat(sockdir, &st)) {
975 if (errno == ENOENT) {
976 if (mkdir(sockdir, 0700)) {
977 perror("noip: creating socketdir");
978 exit(127);
979 }
980 if (!stat(sockdir, &st))
981 goto check;
982 }
983 perror("noip: checking socketdir");
984 exit(127);
985 }
986check:
987 if (!S_ISDIR(st.st_mode)) {
988 printerr("noip: bad socketdir: not a directory\n");
989 exit(127);
990 }
991 if (st.st_uid != uid) {
992 printerr("noip: bad socketdir: not owner\n");
993 exit(127);
994 }
995 if (st.st_mode & 077) {
996 printerr("noip: bad socketdir: not private\n");
997 exit(127);
998 }
999}
1000
e4976bb0 1001static void setup(void)
1002{
1003 PRESERVING_ERRNO({
1004 char *p;
1005
1006 import();
3ef1fec9 1007 uid = geteuid();
e4976bb0 1008 if ((p = getenv("NOIP_DEBUG")) && atoi(p))
1009 debug = 1;
1010 get_local_ipaddrs();
1011 readconfig();
3ef1fec9 1012 create_sockdir();
e4976bb0 1013 cleanup_sockdir();
1014 });
1015}