]> ruderich.org/simon Gitweb - socket2unix/socket2unix.git/blob - src/socket2unix.c
Add --debug option to configure.
[socket2unix/socket2unix.git] / src / socket2unix.c
1 /*
2  * Simple LD_PRELOAD wrapper to "convert" network sockets to UNIX sockets;
3  * works for clients and servers. See README for details.
4  *
5  * Copyright (C) 2013  Simon Ruderich
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21
22 /* Necessary for RTLD_NEXT. */
23 #define _GNU_SOURCE
24
25 #include <config.h>
26
27 #include <assert.h>
28 #include <dlfcn.h>
29 #include <errno.h>
30 #include <netinet/in.h>
31 #include <netinet/ip.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/socket.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <sys/un.h>
40 #include <unistd.h>
41
42
43 /* CONSTANTS */
44
45 #define LOG_LEVEL_ERROR   1
46 #define LOG_LEVEL_WARNING 2
47 #define LOG_LEVEL_DEBUG   3
48 #define LOG_LEVEL_MASK    LOG_LEVEL_DEBUG
49
50 #define LOG_LEVEL_PERROR  42
51
52
53 /* GLOBAL VARIABLES */
54
55 struct list {
56     int unix_sockfd;
57
58     int orig_domain;
59     int orig_type;
60
61     struct list *next;
62 };
63
64 static struct list socket_list = {
65     .unix_sockfd = -1, /* must not match a valid sockfd */
66 };
67
68
69 /* LOG FUNCTIONS/MACROS */
70
71 static int get_log_level(void);
72
73 static void log_helper(int action, const char *file, int line, const char *format, va_list ap) {
74     int saved_errno = errno;
75
76     static int log_level;
77     if (!log_level) {
78         log_level = get_log_level();
79     }
80
81     int level = action & LOG_LEVEL_MASK;
82     if (level > log_level) {
83         return;
84     }
85
86     const char *prefix;
87     if (level == LOG_LEVEL_DEBUG) {
88         prefix = "DEBUG";
89     } else if (level == LOG_LEVEL_WARNING) {
90         prefix = "WARN ";
91     } else if (level == LOG_LEVEL_ERROR) {
92         prefix = "ERROR";
93     } else {
94         prefix = "UNKNOWN";
95     }
96
97     /* Prevent other threads from interrupting the printf()s. */
98     flockfile(stderr);
99
100     fprintf(stderr, "socket2unix [%s] ", prefix);
101     fprintf(stderr, "[%s:%3d] ", file, line);
102     vfprintf(stderr, format, ap);
103
104     if ((action & ~LOG_LEVEL_MASK) == LOG_LEVEL_PERROR) {
105         fprintf(stderr, ": ");
106
107         errno = saved_errno;
108         perror("");
109     }
110
111     funlockfile(stderr);
112
113     if (level == LOG_LEVEL_ERROR) {
114         fprintf(stderr, "Aborting.\n");
115         exit(EXIT_FAILURE);
116     }
117 }
118
119 static void log_(int level, const char *file, int line, const char *format, ...)
120     __attribute__((format(printf, 4, 5)));
121 static void log_(int level, const char *file, int line, const char *format, ...) {
122     va_list ap;
123
124     va_start(ap, format);
125     log_helper(level, file, line, format, ap);
126     va_end(ap);
127 }
128
129 #define ERROR(...) \
130     log_(LOG_LEVEL_ERROR,   __FILE__, __LINE__, __VA_ARGS__)
131 #define WARN(...) \
132     log_(LOG_LEVEL_WARNING, __FILE__, __LINE__, __VA_ARGS__)
133 #define DBG(...) \
134     log_(LOG_LEVEL_DEBUG,   __FILE__, __LINE__, __VA_ARGS__)
135
136 #define DIE(...) \
137     log_(LOG_LEVEL_ERROR | LOG_LEVEL_PERROR, __FILE__, __LINE__, __VA_ARGS__)
138
139
140 /* LD_PRELOAD */
141
142 /* Load the function name using dlsym() if necessary and store it in pointer.
143  * Terminate program on failure. */
144 #define LOAD_FUNCTION(pointer, name) \
145     if ((pointer) == NULL) { \
146         char *error; \
147         dlerror(); /* Clear possibly existing error. */ \
148         \
149         *(void **) (&(pointer)) = dlsym(RTLD_NEXT, (name)); \
150         \
151         if ((error = dlerror()) != NULL) { \
152             ERROR("%s\n", error); \
153         } \
154     }
155
156
157 /* OTHER FUNCTIONS */
158
159 static struct list *find_sockfd(int sockfd) {
160     struct list *e;
161
162     if (sockfd == socket_list.unix_sockfd) {
163         return NULL;
164     }
165
166     for (e = &socket_list; e != NULL; e = e->next) {
167         if (e->unix_sockfd == sockfd) {
168             return e;
169         }
170     }
171     return NULL;
172 }
173 static struct list *remove_sockfd(int sockfd) {
174     struct list *e, *p;
175
176     if (sockfd == socket_list.unix_sockfd) {
177         return NULL;
178     }
179
180     for (e = &socket_list, p = NULL; e != NULL; p = e, e = e->next) {
181         if (e->unix_sockfd == sockfd) {
182             p->next = e->next;
183             return e;
184         }
185     }
186     return NULL;
187 }
188
189 static const char *get_socket_path(void) {
190     const char *path = getenv("SOCKET2UNIX_PATH");
191     if (!path) {
192         ERROR("SOCKET2UNIX_PATH environment variable not defined\n");
193     }
194     if (path[0] != '/') {
195         ERROR("SOCKET2UNIX_PATH '%s' must be an absolute path\n", path);
196     }
197     return path;
198 }
199 static int get_log_level(void) {
200     const char *level = getenv("SOCKET2UNIX_DEBUG");
201     if (!level) {
202 #ifdef DEBUG
203         return LOG_LEVEL_DEBUG;
204 #else
205         return LOG_LEVEL_WARNING;
206 #endif
207     }
208     int number = atoi(level);
209     if (number <= 0 || number > LOG_LEVEL_DEBUG) {
210         number = LOG_LEVEL_DEBUG;
211     }
212     return number;
213 }
214
215 static const char *af_to_name(int af) {
216     if (af == AF_UNIX) {
217         return "AF_UNIX";
218     } else if (af == AF_LOCAL) {
219         return "AF_LOCAL";
220     } else if (af == AF_INET) {
221         return "AF_INET";
222     } else if (af == AF_INET6) {
223         return "AF_INET6";
224     } else if (af == AF_IPX) {
225         return "AF_IPX";
226     } else if (af == AF_NETLINK) {
227         return "AF_NETLINK";
228     } else if (af == AF_X25) {
229         return "AF_X25";
230     } else if (af == AF_AX25) {
231         return "AF_AX25";
232     } else if (af == AF_ATMPVC) {
233         return "AF_ATMPVC";
234     } else if (af == AF_APPLETALK) {
235         return "AF_APPLETALK";
236     } else if (af == AF_PACKET) {
237         return "AF_PACKET";
238     } else {
239         return "AF_UNKNOWN";
240     }
241 }
242 static const char *sock_to_name(int sock) {
243     if (sock & SOCK_STREAM) {
244         return "SOCK_STREAM";
245     } else if (sock & SOCK_DGRAM) {
246         return "SOCK_DGRAM";
247     } else if (sock & SOCK_SEQPACKET) {
248         return "SOCK_SEQPACKET";
249     } else if (sock & SOCK_RAW) {
250         return "SOCK_RAW";
251     } else if (sock & SOCK_RDM) {
252         return "SOCK_RDM";
253     } else if (sock & SOCK_PACKET) {
254         return "SOCK_PACKET";
255     } else {
256         return "SOCK_UNKNOWN";
257     }
258 }
259 /* for getsockopt()/setsockopt(). */
260 static const char *level_to_name(int level) {
261     if (level == SOL_SOCKET) {
262         return "SOL_SOCKET";
263     } else if (level == SOL_IP) {
264         return "SOL_IP";
265     } else if (level == SOL_IPV6) {
266         return "SOL_IPV6";
267     } else if (level == IPPROTO_TCP) {
268         return "IPPROTO_TCP";
269     } else if (level == IPPROTO_UDP) {
270         return "IPPROTO_UDP";
271     } else {
272         return "SOL_UNKNOWN";
273     }
274 }
275
276
277 static int set_sockaddr_un(struct sockaddr_un *sockaddr,
278                            const struct sockaddr *addr, socklen_t addrlen) {
279     /* Just in case ... */
280     if ((addr->sa_family == AF_INET
281                 && addrlen < sizeof(struct sockaddr_in))
282             || (addr->sa_family == AF_INET6
283                 && addrlen < sizeof(struct sockaddr_in6))) {
284         WARN("invalid addrlen from program\n");
285         return -1;
286     }
287
288     const char *socket_path = get_socket_path();
289
290     /* The program may open multiple sockets, e.g. IPv4 and IPv6 and on
291      * multiple ports. Create unique paths. */
292     const char *af;
293     int port;
294     if (addr->sa_family == AF_INET) {
295         af   = "v4";
296         port = ntohs(((struct sockaddr_in *)addr)->sin_port);
297     } else if (addr->sa_family == AF_INET6) {
298         af   = "v6";
299         port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
300     } else {
301         af   = "unknown";
302         port = 0;
303         WARN("unknown sa_family '%s' (%d)\n",
304              af_to_name(addr->sa_family), addr->sa_family);
305     }
306
307     /* Initialize sockaddr_un. */
308     sockaddr->sun_family = AF_UNIX;
309     int written = snprintf(sockaddr->sun_path, sizeof(sockaddr->sun_path),
310                            "%s-%s-%d", socket_path, af, port);
311     /* The maximum length is quite short, check it. */
312     if (written >= (int)sizeof(sockaddr->sun_path)) {
313         ERROR("path '%s-%s-%d' too long for UNIX socket",
314               socket_path, af, port);
315     }
316
317     return 0;
318 }
319
320
321 /* FUNCTIONS OVERWRITTEN BY LD_PRELOAD */
322
323 int socket(int domain, int type, int protocol) {
324     static int (*real_socket)(int, int, int);
325     LOAD_FUNCTION(real_socket, "socket");
326
327     if (domain == AF_UNIX || domain == AF_LOCAL) {
328         return real_socket(domain, type, protocol);
329     }
330
331     DBG("socket(%s, %s, %d)\n",
332         af_to_name(domain), sock_to_name(type), protocol);
333
334     /* We must return the replacement socket in case the program uses select()
335      * or similar on it. */
336
337     int unix_sockfd = real_socket(AF_UNIX, type, 0);
338     if (unix_sockfd < 0) {
339         DIE("bind(): failed to create UNIX socket");
340     }
341
342     struct list *entry = malloc(sizeof(*entry));
343     if (!entry) {
344         DIE("socket(): malloc");
345     }
346     memset(entry, 0, sizeof(*entry));
347
348     entry->unix_sockfd = unix_sockfd;
349     entry->orig_domain = domain;
350     entry->orig_type   = type;
351
352     entry->next = socket_list.next;
353     socket_list.next = entry;
354
355     return unix_sockfd;
356 }
357
358 int close(int fd) {
359     static int (*real_close)(int);
360     LOAD_FUNCTION(real_close, "close");
361
362     DBG("close(%d)\n", fd);
363
364     struct list *entry = remove_sockfd(fd);
365     if (entry == NULL) {
366         DBG("close(%d): sockfd not found\n", fd);
367         return real_close(fd);
368     }
369     assert(fd == entry->unix_sockfd);
370     free(entry);
371
372     return real_close(fd);
373 }
374
375 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
376     static int (*real_bind)(int, const struct sockaddr *, socklen_t);
377     LOAD_FUNCTION(real_bind, "bind");
378
379     DBG("bind(%d, ..)\n", sockfd);
380
381     if (addr == NULL || addrlen < sizeof(addr->sa_family)
382             || addr->sa_family == AF_UNIX
383             || addr->sa_family == AF_LOCAL) {
384         return real_bind(sockfd, addr, addrlen);
385     }
386
387     struct list *entry = find_sockfd(sockfd);
388     if (!entry) {
389         DBG("bind(%d, ..): sockfd not found\n", sockfd);
390         return real_bind(sockfd, addr, addrlen);
391     }
392     assert(sockfd == entry->unix_sockfd);
393     DBG("bind(%d, ..): %s %s\n",
394         sockfd,
395         af_to_name(entry->orig_domain), sock_to_name(entry->orig_type));
396
397     struct sockaddr_un sockaddr;
398     if (set_sockaddr_un(&sockaddr, addr, addrlen) != 0) {
399         ERROR("connect(%d, ..) failed\n", sockfd);
400     }
401
402     DBG("bind(%d, ..): using path '%s'\n", sockfd, sockaddr.sun_path);
403
404     int attempts = 0;
405     while (attempts < 10) {
406         if (real_bind(entry->unix_sockfd, (struct sockaddr *)&sockaddr,
407                                           sizeof(sockaddr)) == 0) {
408             /* Success. */
409             return 0;
410         }
411         if (errno != EADDRINUSE) {
412             DIE("bind(%d, ..): failed to bind to '%s'",
413                 sockfd, sockaddr.sun_path);
414         }
415
416         /* File already exists, unlink it if it's a socket. This has a race
417          * condition, but the worst case is that we delete a file created by
418          * the user at the path he told us to use. Tough luck .. */
419
420         struct stat buf;
421         if (lstat(sockaddr.sun_path, &buf) != 0) {
422             /* Looks like a race, better abort. */
423             DIE("bind(%d, ..): lstat on UNIX socket '%s' failed",
424                 sockfd, sockaddr.sun_path);
425         }
426
427         if (!S_ISSOCK(buf.st_mode)) {
428             ERROR("bind(%d, ..): path '%s' exits and is no socket\n",
429                   sockfd, sockaddr.sun_path);
430         }
431
432         WARN("bind(%d, ..): unlinking '%s'\n", sockfd, sockaddr.sun_path);
433         if (unlink(sockaddr.sun_path) != 0) {
434             DIE("bind(%d, ..): unlink '%s' failed",
435                 sockfd, sockaddr.sun_path);
436         }
437
438         attempts++;
439     }
440
441     ERROR("bind(%d, ..): failed to create UNIX socket file\n", sockfd);
442     return -1; /* never reached */
443 }
444
445 int listen(int sockfd, int backlog) {
446     static int (*real_listen)(int, int);
447     LOAD_FUNCTION(real_listen, "listen");
448
449     DBG("listen(%d, %d)\n", sockfd, backlog);
450
451     struct list *entry = find_sockfd(sockfd);
452     if (!entry) {
453         DBG("listen(%d, %d): sockfd not found\n", sockfd, backlog);
454         return real_listen(sockfd, backlog);
455     }
456     assert(sockfd == entry->unix_sockfd);
457     DBG("listen(%d, %d): %s %s\n",
458         sockfd, backlog,
459         af_to_name(entry->orig_domain), sock_to_name(entry->orig_type));
460
461     if (real_listen(entry->unix_sockfd, backlog) != 0) {
462         DIE("listen(): failed to listen");
463     }
464
465     return 0;
466 }
467
468 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
469     static int (*real_accept)(int, struct sockaddr *, socklen_t *);
470     LOAD_FUNCTION(real_accept, "accept");
471
472     DBG("accept(%d, ..)\n", sockfd);
473
474     struct list *entry = find_sockfd(sockfd);
475     if (!entry) {
476         DBG("accept(%d, ..): sockfd not found\n", sockfd);
477         return real_accept(sockfd, addr, addrlen);
478     }
479     assert(sockfd == entry->unix_sockfd);
480     DBG("accept(%d, ..): %s %s\n",
481         sockfd,
482         af_to_name(entry->orig_domain), sock_to_name(entry->orig_type));
483
484     struct sockaddr_un sockaddr;
485     socklen_t size = sizeof(sockaddr);
486     int sock = real_accept(entry->unix_sockfd, (struct sockaddr *)&sockaddr,
487                                                &size);
488     if (sock < 0) {
489         DIE("accept(%d, ..): failed to accept", sockfd);
490     }
491
492     if (addr == NULL || addrlen == NULL) {
493         return sock;
494     }
495     DBG("accept(%d, ..): caller requested sockaddr\n", sockfd);
496
497     if (*addrlen < size) {
498         WARN("accept(%d, ..): invalid addrlen from program", sockfd);
499         errno = EINVAL;
500         return -1;
501     }
502
503     /* This is not the protocol the program asked for (AF_* vs. AF_UNIX), but
504      * it should work most of the time. */
505     memcpy(addr, &sockaddr, size);
506     *addrlen = size;
507
508     /* TODO: is this enough? */
509
510     return sock;
511 }
512
513 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
514     static int (*real_connect)(int, const struct sockaddr *, socklen_t);
515     LOAD_FUNCTION(real_connect, "connect");
516
517     DBG("connect(%d, ..)\n", sockfd);
518
519     if (addr == NULL || addrlen < sizeof(addr->sa_family)
520             || addr->sa_family == AF_UNIX
521             || addr->sa_family == AF_LOCAL) {
522         return real_connect(sockfd, addr, addrlen);
523     }
524
525     struct list *entry = find_sockfd(sockfd);
526     if (!entry) {
527         DBG("connect(%d, ..): sockfd not found\n", sockfd);
528         return real_connect(sockfd, addr, addrlen);
529     }
530     assert(sockfd == entry->unix_sockfd);
531     DBG("connect(%d, ..): %s %s\n",
532         sockfd,
533         af_to_name(entry->orig_domain), sock_to_name(entry->orig_type));
534
535     struct sockaddr_un sockaddr;
536     if (set_sockaddr_un(&sockaddr, addr, addrlen) != 0) {
537         ERROR("connect(%d, ..) failed\n", sockfd);
538     }
539
540     DBG("connect(%d, ..): using path '%s'\n", sockfd, sockaddr.sun_path);
541
542     if (real_connect(entry->unix_sockfd, (struct sockaddr *)&sockaddr,
543                                          sizeof(sockaddr)) != 0) {
544         DIE("connect(%d, ..): failed to connect", sockfd);
545     }
546
547     return 0;
548 }
549
550
551 int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
552     static int (*real_getsockname)(int, struct sockaddr *, socklen_t *);
553     LOAD_FUNCTION(real_getsockname, "getsockname");
554
555     DBG("getsockname(%d, ..)\n", sockfd);
556
557     return real_getsockname(sockfd, addr, addrlen);
558 }
559
560 int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
561     static int (*real_getpeername)(int, struct sockaddr *, socklen_t *);
562     LOAD_FUNCTION(real_getpeername, "getpeername");
563
564     DBG("getpeername(%d, ..)\n", sockfd);
565
566     return real_getpeername(sockfd, addr, addrlen);
567 }
568
569 int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) {
570     static int (*real_getsockopt)(int, int, int, void *, socklen_t *);
571     LOAD_FUNCTION(real_getsockopt, "getsockopt");
572
573     DBG("getsockopt(%d, %d %s, %d, ..)\n",
574         sockfd, level, level_to_name(level), optname);
575
576     return real_getsockopt(sockfd, level, optname, optval, optlen);
577 }
578 int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) {
579     static int (*real_setsockopt)(int, int, int, const void *, socklen_t);
580     LOAD_FUNCTION(real_setsockopt, "setsockopt");
581
582     DBG("setsockopt(%d, %d %s, %d, ..)\n",
583         sockfd, level, level_to_name(level), optname);
584
585     return real_setsockopt(sockfd, level, optname, optval, optlen);
586 }