Skip to content

Commit

Permalink
Merge unix socket [email protected]
Browse files Browse the repository at this point in the history
  • Loading branch information
mkj committed Apr 3, 2024
2 parents 1ee38fe + 65dbc7b commit 1d5f63c
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ struct ChanType {
void (*cleanup)(const struct Channel*);
};

/* Callback for connect_remote. errstring may be NULL if result == DROPBEAR_SUCCESS */
/* Callback for connect_remote/connect_streamlocal. errstring may be NULL if result == DROPBEAR_SUCCESS */
void channel_connect_done(int result, int sock, void* user_data, const char* errstring);

void chaninitialise(const struct ChanType *chantypes[]);
Expand Down
1 change: 1 addition & 0 deletions src/default_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ IMPORTANT: Some options will require "make clean" after changes */

#define DROPBEAR_SVR_LOCALTCPFWD 1
#define DROPBEAR_SVR_REMOTETCPFWD 1
#define DROPBEAR_SVR_LOCALSTREAMFWD 1

/* Enable Authentication Agent Forwarding */
#define DROPBEAR_SVR_AGENTFWD 1
Expand Down
69 changes: 66 additions & 3 deletions src/netio.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ struct dropbear_progress_connection {
Does not close sockets */
static void remove_connect(struct dropbear_progress_connection *c, m_list_elem *iter) {
if (c->res) {
freeaddrinfo(c->res);
/* Only call freeaddrinfo if connection is not AF_UNIX. */
if (c->res->ai_family != AF_UNIX) {
freeaddrinfo(c->res);
} else {
m_free(c->res);
}
}
m_free(c->remotehost);
m_free(c->remoteport);
Expand Down Expand Up @@ -59,6 +64,7 @@ static void connect_try_next(struct dropbear_progress_connection *c) {
int err;
int res = 0;
int fastopen = 0;
int retry_errno = EINPROGRESS;
#if DROPBEAR_CLIENT_TCP_FAST_OPEN
struct msghdr message;
#endif
Expand All @@ -72,6 +78,11 @@ static void connect_try_next(struct dropbear_progress_connection *c) {
continue;
}

/* According to the connect(2) manpage it should be testing EAGAIN
* rather than EINPROGRESS for unix sockets.
*/
retry_errno = r->ai_family == AF_UNIX ? EAGAIN : EINPROGRESS;

if (c->bind_address || c->bind_port) {
/* bind to a source port/address */
struct addrinfo hints;
Expand Down Expand Up @@ -116,7 +127,7 @@ static void connect_try_next(struct dropbear_progress_connection *c) {
setnonblocking(c->sock);

#if DROPBEAR_CLIENT_TCP_FAST_OPEN
fastopen = (c->writequeue != NULL);
fastopen = (c->writequeue != NULL && r->ai_family != AF_UNIX);

if (fastopen) {
memset(&message, 0x0, sizeof(message));
Expand Down Expand Up @@ -153,7 +164,7 @@ static void connect_try_next(struct dropbear_progress_connection *c) {
res = connect(c->sock, r->ai_addr, r->ai_addrlen);
}

if (res < 0 && errno != EINPROGRESS) {
if (res < 0 && errno != retry_errno) {
/* failure */
m_free(c->errstring);
c->errstring = m_strdup(strerror(errno));
Expand Down Expand Up @@ -225,6 +236,58 @@ struct dropbear_progress_connection *connect_remote(const char* remotehost, cons
return c;
}


/* Connect to stream local socket. */
struct dropbear_progress_connection *connect_streamlocal(const char* localpath,
connect_callback cb, void* cb_data, enum dropbear_prio prio)
{
struct dropbear_progress_connection *c = NULL;
struct sockaddr_un *sunaddr;

c = m_malloc(sizeof(*c));
c->remotehost = m_strdup(localpath);
c->remoteport = NULL;
c->sock = -1;
c->cb = cb;
c->cb_data = cb_data;
c->prio = prio;

list_append(&ses.conn_pending, c);

#if DROPBEAR_FUZZ
if (fuzz.fuzzing) {
c->errstring = m_strdup("fuzzing connect_streamlocal always fails");
return c;
}
#endif

if (strlen(localpath) >= sizeof(sunaddr->sun_path)) {
c->errstring = m_strdup("Stream path too long");
TRACE(("localpath: %s is too long", localpath));
return c;
}

/*
* Fake up a struct addrinfo for AF_UNIX connections.
* remove_connect() must check ai_family
* and use m_free() not freeaddirinfo() for AF_UNIX.
*/
c->res = m_malloc(sizeof(*c->res) + sizeof(*sunaddr));
c->res->ai_addr = (struct sockaddr *)(c->res + 1);
c->res->ai_addrlen = sizeof(*sunaddr);
c->res->ai_family = AF_UNIX;
c->res->ai_socktype = SOCK_STREAM;
c->res->ai_protocol = PF_UNSPEC;
sunaddr = (struct sockaddr_un *)c->res->ai_addr;
sunaddr->sun_family = AF_UNIX;
strlcpy(sunaddr->sun_path, localpath, sizeof(sunaddr->sun_path));

/* Copy to target iter */
c->res_iter = c->res;

return c;
}

void remove_connect_pending() {
while (ses.conn_pending.first) {
struct dropbear_progress_connection *c = ses.conn_pending.first->item;
Expand Down
5 changes: 5 additions & 0 deletions src/netio.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ struct dropbear_progress_connection * connect_remote (const char* remotehost, co
connect_callback cb, void *cb_data, const char* bind_address, const char* bind_port,
enum dropbear_prio prio);

/* Connect to local stream, always returns a progress connection, if it fails it will call the callback at a later point */
struct dropbear_progress_connection * connect_streamlocal (const char* localpath,
connect_callback cb, void *cb_data,
enum dropbear_prio prio);

/* Sets up for select() */
void set_connect_fds(fd_set *writefd);
/* Handles ready sockets after select() */
Expand Down
3 changes: 3 additions & 0 deletions src/svr-session.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ static const struct ChanType *svr_chantypes[] = {
&svrchansess,
#if DROPBEAR_SVR_LOCALTCPFWD
&svr_chan_tcpdirect,
#endif
#if DROPBEAR_SVR_LOCALSTREAMFWD
&svr_chan_streamlocal,
#endif
NULL /* Null termination is mandatory. */
};
Expand Down
55 changes: 55 additions & 0 deletions src/svr-tcpfwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ void recv_msg_global_request_remotetcp() {
static int svr_cancelremotetcp(void);
static int svr_remotetcpreq(int *allocated_listen_port);
static int newtcpdirect(struct Channel * channel);
static int newstreamlocal(struct Channel * channel);

#if DROPBEAR_SVR_REMOTETCPFWD
static const struct ChanType svr_chan_tcpremote = {
Expand Down Expand Up @@ -309,3 +310,57 @@ static int newtcpdirect(struct Channel * channel) {
}

#endif /* DROPBEAR_SVR_LOCALTCPFWD */


#if DROPBEAR_SVR_LOCALSTREAMFWD

const struct ChanType svr_chan_streamlocal = {
"[email protected]",
newstreamlocal, /* init */
NULL, /* checkclose */
NULL, /* reqhandler */
NULL, /* closehandler */
NULL /* cleanup */
};

/* Called upon creating a new stream local channel (ie we connect out to an
* address */
static int newstreamlocal(struct Channel * channel) {

/*
https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL#rev1.30
byte SSH_MSG_CHANNEL_OPEN
string "[email protected]"
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
string socket path
string reserved
uint32 reserved
*/

char* destsocket = NULL;
unsigned int len;
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;

TRACE(("streamlocal channel %d", channel->index))

destsocket = buf_getstring(ses.payload, &len);
if (len > MAX_HOST_LEN) {
TRACE(("leave streamlocal: destsocket too long"))
goto out;
}

channel->conn_pending = connect_streamlocal(destsocket, channel_connect_done,
channel, DROPBEAR_PRIO_NORMAL);

err = SSH_OPEN_IN_PROGRESS;

out:
m_free(destsocket);
TRACE(("leave streamlocal: err %d", err))
return err;
}

#endif /* DROPBEAR_SVR_LOCALSTREAMFWD */
2 changes: 2 additions & 0 deletions src/tcpfwd.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ void recv_msg_global_request_remotetcp(void);

extern const struct ChanType svr_chan_tcpdirect;

extern const struct ChanType svr_chan_streamlocal;

/* Client */
void setup_localtcp(void);
void setup_remotetcp(void);
Expand Down

0 comments on commit 1d5f63c

Please sign in to comment.