1 /* sockprox - Proxy for local sockets with logging facilities
2 * Copyright (C) 2007 g10 Code GmbH.
4 * sockprox is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
9 * sockprox is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 /* Hacked by Moritz Schulte <moritz@g10code.com>.
22 Run a server which binds to a local socket. For example,
23 gpg-agent. gpg-agent's local socket is specified with --server.
24 sockprox opens a new local socket (here "mysock"); the whole
25 traffic between server and client is written to "/tmp/prot" in this
28 ./sockprox --server /tmp/gpg-PKdD8r/S.gpg-agent.ssh \
29 --listen mysock --protocol /tmp/prot
31 Then, redirect your ssh-agent client to sockprox by setting
32 SSH_AUTH_SOCK to "mysock".
44 #include <sys/socket.h>
58 struct opt opt
= { NULL
, NULL
, NULL
, 0 };
69 create_server_socket (const char *filename
, int *new_sock
)
71 struct sockaddr_un name
;
77 /* Create the socket. */
78 sock
= socket (PF_LOCAL
, SOCK_STREAM
, 0);
85 /* Bind a name to the socket. */
86 name
.sun_family
= AF_LOCAL
;
87 strncpy (name
.sun_path
, filename
, sizeof (name
.sun_path
));
88 name
.sun_path
[sizeof (name
.sun_path
) - 1] = '\0';
89 size
= SUN_LEN (&name
);
93 ret
= bind (sock
, (struct sockaddr
*) &name
, size
);
100 ret
= listen (sock
, 2);
116 connect_to_socket (const char *filename
, int *new_sock
)
118 struct sockaddr_un srvr_addr
;
124 sock
= socket (PF_LOCAL
, SOCK_STREAM
, 0);
131 memset (&srvr_addr
, 0, sizeof srvr_addr
);
132 srvr_addr
.sun_family
= AF_LOCAL
;
133 strncpy (srvr_addr
.sun_path
, filename
, sizeof (srvr_addr
.sun_path
) - 1);
134 srvr_addr
.sun_path
[sizeof (srvr_addr
.sun_path
) - 1] = 0;
135 len
= SUN_LEN (&srvr_addr
);
137 ret
= connect (sock
, (struct sockaddr
*) &srvr_addr
, len
);
156 log_data (unsigned char *data
, size_t length
,
157 FILE *from
, FILE *to
, FILE *protocol
)
163 flockfile (protocol
);
164 fprintf (protocol
, "%i -> %i: ", fileno (from
), fileno (to
));
165 for (i
= 0; i
< length
; i
++)
166 fprintf (protocol
, "%02X", data
[i
]);
167 fprintf (protocol
, "\n");
168 funlockfile (protocol
);
170 ret
= fflush (protocol
);
180 transfer_data (FILE *from
, FILE *to
, FILE *protocol
)
182 unsigned char buffer
[BUFSIZ
];
191 len
= fread (buffer
, 1, sizeof (buffer
), from
);
195 err
= log_data (buffer
, len
, from
, to
, protocol
);
199 written
= fwrite (buffer
, 1, len
, to
);
222 io_loop (FILE *client
, FILE *server
, FILE *protocol
)
224 fd_set active_fd_set
, read_fd_set
;
228 FD_ZERO (&active_fd_set
);
229 FD_SET (fileno (client
), &active_fd_set
);
230 FD_SET (fileno (server
), &active_fd_set
);
236 read_fd_set
= active_fd_set
;
240 ret
= select (FD_SETSIZE
, &read_fd_set
, NULL
, NULL
, NULL
);
247 if (FD_ISSET (fileno (client
), &read_fd_set
))
252 /* Forward data from client to server. */
253 err
= transfer_data (client
, server
, protocol
);
255 else if (FD_ISSET (fileno (server
), &read_fd_set
))
260 /* Forward data from server to client. */
261 err
= transfer_data (server
, client
, protocol
);
274 /* Set the `O_NONBLOCK' flag of DESC if VALUE is nonzero,
275 or clear the flag if VALUE is 0.
276 Return 0 on success, or -1 on error with `errno' set. */
279 set_nonblock_flag (int desc
, int value
)
281 int oldflags
= fcntl (desc
, F_GETFL
, 0);
285 /* If reading the flags failed, return error indication now. */
288 /* Set just the flag we want to set. */
290 oldflags
|= O_NONBLOCK
;
292 oldflags
&= ~O_NONBLOCK
;
293 /* Store modified flag word in the descriptor. */
295 ret
= fcntl (desc
, F_SETFL
, oldflags
);
307 serve_client (void *data
)
309 struct thread_data
*thread_data
= data
;
310 int client_sock
= thread_data
->client_sock
;
312 FILE *protocol
= thread_data
->protocol_file
;
320 /* Connect to server. */
321 err
= connect_to_socket (opt
.server_spec
, &server_sock
);
325 /* Set IO mode to nonblicking. */
326 err
= set_nonblock_flag (server_sock
, 1);
330 client
= fdopen (client_sock
, "r+");
337 server
= fdopen (server_sock
, "r+");
344 err
= io_loop (client
, server
, protocol
);
369 struct sockaddr_un clientname
;
372 struct thread_data
*thread_data
;
374 pthread_attr_t thread_attr
;
376 protocol_file
= NULL
;
378 err
= pthread_attr_init (&thread_attr
);
382 err
= pthread_attr_setdetachstate (&thread_attr
, PTHREAD_CREATE_DETACHED
);
386 if (opt
.protocol_file
)
388 protocol_file
= fopen (opt
.protocol_file
, "a");
396 protocol_file
= stdout
;
398 err
= create_server_socket (opt
.listen_spec
, &my_sock
);
404 /* Accept new client. */
405 size
= sizeof (clientname
);
406 client_sock
= accept (my_sock
,
407 (struct sockaddr
*) &clientname
,
415 /* Set IO mode to nonblicking. */
416 err
= set_nonblock_flag (client_sock
, 1);
423 /* Got new client -> handle in new process. */
425 thread_data
= malloc (sizeof (*thread_data
));
431 thread_data
->client_sock
= client_sock
;
432 thread_data
->protocol_file
= protocol_file
;
434 err
= pthread_create (&mythread
, &thread_attr
, serve_client
, thread_data
);
445 pthread_attr_destroy (&thread_attr
);
446 fclose (protocol_file
); /* FIXME, err checking. */
456 printf ("Usage: sockprox [options] "
457 "--server SERVER-SOCKET --listen PROXY-SOCKET\n");
462 main (int argc
, char **argv
)
464 struct option long_options
[] =
466 { "help", no_argument
, 0, 'h' },
467 { "verbose", no_argument
, &opt
.verbose
, 1 },
468 { "protocol", required_argument
, 0, 'p' },
469 { "server", required_argument
, 0, 's' },
470 { "listen", required_argument
, 0, 'l' },
480 c
= getopt_long (argc
, argv
, "hvp:s:l:",
481 long_options
, &opt_idx
);
489 if (long_options
[opt_idx
].flag
)
491 printf ("option %s", long_options
[opt_idx
].name
);
493 printf (" with arg %s", optarg
);
498 opt
.protocol_file
= optarg
;
502 opt
.server_spec
= optarg
;
506 opt
.listen_spec
= optarg
;
514 print_help (EXIT_SUCCESS
);
524 printf ("server: %s\n", opt
.server_spec
? opt
.server_spec
: "");
525 printf ("listen: %s\n", opt
.listen_spec
? opt
.listen_spec
: "");
526 printf ("protocol: %s\n", opt
.protocol_file
? opt
.protocol_file
: "");
529 if (! (opt
.server_spec
&& opt
.listen_spec
))
530 print_help (EXIT_FAILURE
);
535 fprintf (stderr
, "run_proxy() failed: %s\n", strerror (err
));
548 compile-command: "cc -Wall -g -o sockprox sockprox.c -lpthread"