for communication instead of TCP. This allows you to forward the connection over ssh in a secure maner. Though you can forward TCP sessions over ssh, it doesn't implement authentication, so ANYONE on the box could end up accessing the disks. With socks you can use file system permissions to restrict them.tags/ggatessh-v1.0.0
@@ -49,6 +49,7 @@ | |||
#include <sys/syslog.h> | |||
#include <sys/time.h> | |||
#include <sys/bio.h> | |||
#include <sys/un.h> | |||
#include <netinet/in.h> | |||
#include <netinet/tcp.h> | |||
#include <arpa/inet.h> | |||
@@ -56,6 +57,7 @@ | |||
#include <geom/gate/g_gate.h> | |||
#include "ggate.h" | |||
static const char *sockprefix = "sock:"; | |||
static enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET; | |||
@@ -246,37 +248,70 @@ handshake(int dir) | |||
struct g_gate_version ver; | |||
struct g_gate_cinit cinit; | |||
struct g_gate_sinit sinit; | |||
struct sockaddr_in serv; | |||
struct sockaddr *serv; | |||
struct sockaddr_in inaddr; | |||
struct sockaddr_un unixaddr; | |||
socklen_t addrlen; | |||
int sfd; | |||
const char *sockname; | |||
sockname = NULL; | |||
/* | |||
* Do the network stuff. | |||
*/ | |||
bzero(&serv, sizeof(serv)); | |||
serv.sin_family = AF_INET; | |||
serv.sin_addr.s_addr = g_gate_str2ip(host); | |||
if (serv.sin_addr.s_addr == INADDR_NONE) { | |||
g_gate_log(LOG_DEBUG, "Invalid IP/host name: %s.", host); | |||
return (-1); | |||
} | |||
serv.sin_port = htons(port); | |||
sfd = socket(AF_INET, SOCK_STREAM, 0); | |||
if (sfd == -1) { | |||
g_gate_log(LOG_DEBUG, "Cannot open socket: %s.", | |||
strerror(errno)); | |||
return (-1); | |||
} | |||
if (strncmp(host, sockprefix, strlen(sockprefix)) == 0) { | |||
sockname = host + strlen(sockprefix); | |||
if (strlen(sockname) + 1 > sizeof(unixaddr.sun_path)) { | |||
g_gate_log(LOG_DEBUG, "Socket path is too long."); | |||
return (-1); | |||
} | |||
g_gate_socket_settings(sfd); | |||
unixaddr = (struct sockaddr_un) { | |||
.sun_len = sizeof(unixaddr), | |||
.sun_family = AF_UNIX, | |||
}; | |||
strncpy(unixaddr.sun_path, sockname, sizeof(unixaddr.sun_path)); | |||
sfd = socket(AF_UNIX, SOCK_STREAM, 0); | |||
if (sfd == -1) { | |||
g_gate_log(LOG_DEBUG, "Cannot open socket: %s.", | |||
strerror(errno)); | |||
return (-1); | |||
} | |||
serv = (struct sockaddr *)&unixaddr; | |||
addrlen = sizeof unixaddr; | |||
} else { | |||
bzero(&inaddr, sizeof(inaddr)); | |||
inaddr.sin_family = AF_INET; | |||
inaddr.sin_addr.s_addr = g_gate_str2ip(host); | |||
if (inaddr.sin_addr.s_addr == INADDR_NONE) { | |||
g_gate_log(LOG_DEBUG, "Invalid IP/host name: %s.", host); | |||
return (-1); | |||
} | |||
inaddr.sin_port = htons(port); | |||
sfd = socket(AF_INET, SOCK_STREAM, 0); | |||
if (sfd == -1) { | |||
g_gate_log(LOG_DEBUG, "Cannot open socket: %s.", | |||
strerror(errno)); | |||
return (-1); | |||
} | |||
if (connect(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) { | |||
serv = (struct sockaddr *)&inaddr; | |||
addrlen = sizeof inaddr; | |||
g_gate_socket_settings(sfd); | |||
} | |||
if (connect(sfd, serv, addrlen) == -1) { | |||
g_gate_log(LOG_DEBUG, "Cannot connect to server: %s.", | |||
strerror(errno)); | |||
close(sfd); | |||
return (-1); | |||
} | |||
g_gate_log(LOG_INFO, "Connected to the server: %s:%d.", host, port); | |||
if (sockname != NULL) | |||
g_gate_log(LOG_INFO, "Connected to socket: %s.", sockname); | |||
else | |||
g_gate_log(LOG_INFO, "Connected to the server: %s:%d.", host, port); | |||
/* | |||
* Create and send version packet. | |||
@@ -37,6 +37,7 @@ | |||
#include <sys/socket.h> | |||
#include <sys/stat.h> | |||
#include <sys/time.h> | |||
#include <sys/un.h> | |||
#include <arpa/inet.h> | |||
#include <netinet/in.h> | |||
#include <netinet/tcp.h> | |||
@@ -96,7 +97,6 @@ struct ggd_export { | |||
static const char *exports_file = GGATED_EXPORT_FILE; | |||
static int got_sighup = 0; | |||
static in_addr_t bindaddr; | |||
static TAILQ_HEAD(, ggd_request) inqueue = TAILQ_HEAD_INITIALIZER(inqueue); | |||
static TAILQ_HEAD(, ggd_request) outqueue = TAILQ_HEAD_INITIALIZER(outqueue); | |||
@@ -115,7 +115,7 @@ usage(void) | |||
{ | |||
fprintf(stderr, "usage: %s [-nv] [-a address] [-F pidfile] [-p port] " | |||
"[-R rcvbuf] [-S sndbuf] [exports file]\n", getprogname()); | |||
"[-R rcvbuf] [-S sndbuf] [-s socket] [exports file]\n", getprogname()); | |||
exit(EXIT_FAILURE); | |||
} | |||
@@ -948,21 +948,76 @@ huphandler(int sig __unused) | |||
got_sighup = 1; | |||
} | |||
/* | |||
* If sockaddr is not NULL, bind to the Unix domain socket at sockname, | |||
* otherwise bind to the INET addr:port | |||
*/ | |||
static int | |||
bindsocket(in_addr_t bindaddr, int port, char *sockname) | |||
{ | |||
struct sockaddr_un unixaddr; | |||
struct sockaddr_in serv; | |||
int sfd; | |||
g_gate_log(LOG_INFO, "binding socket"); | |||
if (sockname != NULL) { | |||
if (strlen(sockname) + 1 > sizeof(unixaddr.sun_path)) | |||
g_gate_xlog("Socket path is too long."); | |||
sfd = socket(AF_UNIX, SOCK_STREAM, 0); | |||
if (sfd == -1) | |||
g_gate_xlog("Cannot open stream socket: %s.", strerror(errno)); | |||
unixaddr = (struct sockaddr_un) { | |||
.sun_len = sizeof(unixaddr), | |||
.sun_family = AF_UNIX, | |||
}; | |||
strncpy(unixaddr.sun_path, sockname, sizeof(unixaddr.sun_path)); | |||
if (bind(sfd, (struct sockaddr *)&unixaddr, sizeof(unixaddr)) == -1) | |||
g_gate_xlog("bind(): %s.", strerror(errno)); | |||
if (listen(sfd, 5) == -1) | |||
g_gate_xlog("listen(): %s.", strerror(errno)); | |||
g_gate_log(LOG_INFO, "Listen on path: %s.", sockname); | |||
} else { | |||
sfd = socket(AF_INET, SOCK_STREAM, 0); | |||
if (sfd == -1) | |||
g_gate_xlog("Cannot open stream socket: %s.", strerror(errno)); | |||
bzero(&serv, sizeof(serv)); | |||
serv.sin_family = AF_INET; | |||
serv.sin_addr.s_addr = bindaddr; | |||
serv.sin_port = htons(port); | |||
g_gate_socket_settings(sfd); | |||
if (bind(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) | |||
g_gate_xlog("bind(): %s.", strerror(errno)); | |||
if (listen(sfd, 5) == -1) | |||
g_gate_xlog("listen(): %s.", strerror(errno)); | |||
g_gate_log(LOG_INFO, "Listen on port: %d.", port); | |||
} | |||
return sfd; | |||
} | |||
int | |||
main(int argc, char *argv[]) | |||
{ | |||
const char *ggated_pidfile = _PATH_VARRUN "/ggated.pid"; | |||
char *sockname = NULL; | |||
struct pidfh *pfh; | |||
struct sockaddr_in serv; | |||
struct sockaddr from; | |||
socklen_t fromlen; | |||
in_addr_t bindaddr; | |||
pid_t otherpid; | |||
int ch, sfd, tmpsfd; | |||
unsigned port; | |||
bindaddr = htonl(INADDR_ANY); | |||
port = G_GATE_PORT; | |||
while ((ch = getopt(argc, argv, "a:hnp:F:R:S:v")) != -1) { | |||
while ((ch = getopt(argc, argv, "a:hnp:F:R:S:s:v")) != -1) { | |||
switch (ch) { | |||
case 'a': | |||
bindaddr = g_gate_str2ip(optarg); | |||
@@ -995,6 +1050,9 @@ main(int argc, char *argv[]) | |||
if (sndbuf == 0 && errno != 0) | |||
errx(EXIT_FAILURE, "Invalid sndbuf."); | |||
break; | |||
case 's': | |||
sockname = strdup(optarg); | |||
break; | |||
case 'v': | |||
g_gate_verbose++; | |||
break; | |||
@@ -1019,33 +1077,21 @@ main(int argc, char *argv[]) | |||
err(EXIT_FAILURE, "Cannot open/create pidfile"); | |||
} | |||
signal(SIGCHLD, SIG_IGN); | |||
sfd = bindsocket(bindaddr, port, sockname); | |||
if (!g_gate_verbose) { | |||
FILE *t = fopen("local.log", "w"); | |||
/* Run in daemon mode. */ | |||
if (daemon(0, 0) == -1) | |||
g_gate_xlog("Cannot daemonize: %s", strerror(errno)); | |||
stderr = t; | |||
} | |||
pidfile_write(pfh); | |||
signal(SIGCHLD, SIG_IGN); | |||
sfd = socket(AF_INET, SOCK_STREAM, 0); | |||
if (sfd == -1) | |||
g_gate_xlog("Cannot open stream socket: %s.", strerror(errno)); | |||
bzero(&serv, sizeof(serv)); | |||
serv.sin_family = AF_INET; | |||
serv.sin_addr.s_addr = bindaddr; | |||
serv.sin_port = htons(port); | |||
g_gate_socket_settings(sfd); | |||
if (bind(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) | |||
g_gate_xlog("bind(): %s.", strerror(errno)); | |||
if (listen(sfd, 5) == -1) | |||
g_gate_xlog("listen(): %s.", strerror(errno)); | |||
g_gate_log(LOG_INFO, "Listen on port: %d.", port); | |||
signal(SIGHUP, huphandler); | |||
for (;;) { | |||
@@ -123,11 +123,55 @@ ggatel_md_cleanup() | |||
common_cleanup | |||
} | |||
atf_test_case ggate_sock cleanup | |||
ggate_sock_head() | |||
{ | |||
atf_set "descr" "ggatec can connect to ggated over unix domain socket" | |||
atf_set "require.progs" "ggatec ggated" | |||
atf_set "require.user" "root" | |||
atf_set "timeout" 5 | |||
} | |||
ggate_sock_body() | |||
{ | |||
load_ggate | |||
us=$(alloc_ggate_dev) | |||
work=$(alloc_md) | |||
src=$(alloc_md) | |||
atf_check -e ignore -o ignore \ | |||
dd if=/dev/random of=/dev/$work bs=1m count=1 conv=notrunc | |||
atf_check -e ignore -o ignore \ | |||
dd if=/dev/random of=/dev/$src bs=1m count=1 conv=notrunc | |||
echo $CONF >> $PLAINFILES | |||
echo "0.0.0.0 RW /dev/$work" > $CONF | |||
atf_check ggated -s local.sock -F $PIDFILE $CONF | |||
atf_check ggatec create -u $us sock:"$(pwd)/local.sock" /dev/$work | |||
ggate_dev=/dev/ggate${us} | |||
wait_for_ggate_device ${ggate_dev} | |||
atf_check -e ignore -o ignore \ | |||
dd if=/dev/${src} of=${ggate_dev} bs=1m count=1 conv=notrunc | |||
checksum /dev/$src /dev/$work | |||
} | |||
ggate_sock_cleanup() | |||
{ | |||
common_cleanup | |||
} | |||
atf_init_test_cases() | |||
{ | |||
atf_add_test_case ggated | |||
atf_add_test_case ggatel_file | |||
atf_add_test_case ggatel_md | |||
atf_add_test_case ggate_sock | |||
} | |||
alloc_ggate_dev() | |||