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';
90 size
= SUN_LEN (&name
);
94 ret
= bind (sock
, (struct sockaddr
*) &name
, size
);
101 ret
= listen (sock
, 2);
117 connect_to_socket (const char *filename
, int *new_sock
)
119 struct sockaddr_un srvr_addr
;
125 sock
= socket (PF_LOCAL
, SOCK_STREAM
, 0);
132 memset (&srvr_addr
, 0, sizeof srvr_addr
);
133 srvr_addr
.sun_family
= AF_LOCAL
;
134 strncpy (srvr_addr
.sun_path
, filename
, sizeof (srvr_addr
.sun_path
) - 1);
135 srvr_addr
.sun_path
[sizeof (srvr_addr
.sun_path
) - 1] = 0;
136 len
= SUN_LEN (&srvr_addr
);
138 ret
= connect (sock
, (struct sockaddr
*) &srvr_addr
, len
);
157 log_data (unsigned char *data
, size_t length
,
158 FILE *from
, FILE *to
, FILE *protocol
)
164 flockfile (protocol
);
165 fprintf (protocol
, "%i -> %i: ", fileno (from
), fileno (to
));
166 for (i
= 0; i
< length
; i
++)
167 fprintf (protocol
, "%02X", data
[i
]);
168 fprintf (protocol
, "\n");
169 funlockfile (protocol
);
171 ret
= fflush (protocol
);
181 transfer_data (FILE *from
, FILE *to
, FILE *protocol
)
183 unsigned char buffer
[BUFSIZ
];
192 len
= fread (buffer
, 1, sizeof (buffer
), from
);
196 err
= log_data (buffer
, len
, from
, to
, protocol
);
200 written
= fwrite (buffer
, 1, len
, to
);
223 io_loop (FILE *client
, FILE *server
, FILE *protocol
)
225 fd_set active_fd_set
, read_fd_set
;
229 FD_ZERO (&active_fd_set
);
230 FD_SET (fileno (client
), &active_fd_set
);
231 FD_SET (fileno (server
), &active_fd_set
);
237 read_fd_set
= active_fd_set
;
241 ret
= select (FD_SETSIZE
, &read_fd_set
, NULL
, NULL
, NULL
);
248 if (FD_ISSET (fileno (client
), &read_fd_set
))
253 /* Forward data from client to server. */
254 err
= transfer_data (client
, server
, protocol
);
256 else if (FD_ISSET (fileno (server
), &read_fd_set
))
261 /* Forward data from server to client. */
262 err
= transfer_data (server
, client
, protocol
);
275 /* Set the `O_NONBLOCK' flag of DESC if VALUE is nonzero,
276 or clear the flag if VALUE is 0.
277 Return 0 on success, or -1 on error with `errno' set. */
280 set_nonblock_flag (int desc
, int value
)
282 int oldflags
= fcntl (desc
, F_GETFL
, 0);
286 /* If reading the flags failed, return error indication now. */
289 /* Set just the flag we want to set. */
291 oldflags
|= O_NONBLOCK
;
293 oldflags
&= ~O_NONBLOCK
;
294 /* Store modified flag word in the descriptor. */
296 ret
= fcntl (desc
, F_SETFL
, oldflags
);
308 serve_client (void *data
)
310 struct thread_data
*thread_data
= data
;
311 int client_sock
= thread_data
->client_sock
;
313 FILE *protocol
= thread_data
->protocol_file
;
321 /* Connect to server. */
322 err
= connect_to_socket (opt
.server_spec
, &server_sock
);
326 /* Set IO mode to nonblicking. */
327 err
= set_nonblock_flag (server_sock
, 1);
331 client
= fdopen (client_sock
, "r+");
338 server
= fdopen (server_sock
, "r+");
345 err
= io_loop (client
, server
, protocol
);
370 struct sockaddr_un clientname
;
373 struct thread_data
*thread_data
;
375 pthread_attr_t thread_attr
;
377 protocol_file
= NULL
;
379 err
= pthread_attr_init (&thread_attr
);
383 err
= pthread_attr_setdetachstate (&thread_attr
, PTHREAD_CREATE_DETACHED
);
387 if (opt
.protocol_file
)
389 protocol_file
= fopen (opt
.protocol_file
, "a");
397 protocol_file
= stdout
;
399 err
= create_server_socket (opt
.listen_spec
, &my_sock
);
405 /* Accept new client. */
406 size
= sizeof (clientname
);
407 client_sock
= accept (my_sock
,
408 (struct sockaddr
*) &clientname
,
416 /* Set IO mode to nonblicking. */
417 err
= set_nonblock_flag (client_sock
, 1);
424 /* Got new client -> handle in new process. */
426 thread_data
= malloc (sizeof (*thread_data
));
432 thread_data
->client_sock
= client_sock
;
433 thread_data
->protocol_file
= protocol_file
;
435 err
= pthread_create (&mythread
, &thread_attr
, serve_client
, thread_data
);
446 pthread_attr_destroy (&thread_attr
);
447 fclose (protocol_file
); /* FIXME, err checking. */
457 printf ("Usage: sockprox [options] "
458 "--server SERVER-SOCKET --listen PROXY-SOCKET\n");
463 main (int argc
, char **argv
)
465 struct option long_options
[] =
467 { "help", no_argument
, 0, 'h' },
468 { "verbose", no_argument
, &opt
.verbose
, 1 },
469 { "protocol", required_argument
, 0, 'p' },
470 { "server", required_argument
, 0, 's' },
471 { "listen", required_argument
, 0, 'l' },
481 c
= getopt_long (argc
, argv
, "hvp:s:l:",
482 long_options
, &opt_idx
);
490 if (long_options
[opt_idx
].flag
)
492 printf ("option %s", long_options
[opt_idx
].name
);
494 printf (" with arg %s", optarg
);
499 opt
.protocol_file
= optarg
;
503 opt
.server_spec
= optarg
;
507 opt
.listen_spec
= optarg
;
515 print_help (EXIT_SUCCESS
);
525 printf ("server: %s\n", opt
.server_spec
? opt
.server_spec
: "");
526 printf ("listen: %s\n", opt
.listen_spec
? opt
.listen_spec
: "");
527 printf ("protocol: %s\n", opt
.protocol_file
? opt
.protocol_file
: "");
530 if (! (opt
.server_spec
&& opt
.listen_spec
))
531 print_help (EXIT_FAILURE
);
536 fprintf (stderr
, "run_proxy() failed: %s\n", strerror (err
));
549 compile-command: "cc -Wall -g -o sockprox sockprox.c -lpthread"