Skip to content

Commit 1d5f63c

Browse files
committed
Merge unix socket direct-streamlocal@openssh.com
PR #199
2 parents 1ee38fe + 65dbc7b commit 1d5f63c

File tree

7 files changed

+133
-4
lines changed

7 files changed

+133
-4
lines changed

src/channel.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ struct ChanType {
102102
void (*cleanup)(const struct Channel*);
103103
};
104104

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

108108
void chaninitialise(const struct ChanType *chantypes[]);

src/default_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ IMPORTANT: Some options will require "make clean" after changes */
7373

7474
#define DROPBEAR_SVR_LOCALTCPFWD 1
7575
#define DROPBEAR_SVR_REMOTETCPFWD 1
76+
#define DROPBEAR_SVR_LOCALSTREAMFWD 1
7677

7778
/* Enable Authentication Agent Forwarding */
7879
#define DROPBEAR_SVR_AGENTFWD 1

src/netio.c

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ struct dropbear_progress_connection {
2828
Does not close sockets */
2929
static void remove_connect(struct dropbear_progress_connection *c, m_list_elem *iter) {
3030
if (c->res) {
31-
freeaddrinfo(c->res);
31+
/* Only call freeaddrinfo if connection is not AF_UNIX. */
32+
if (c->res->ai_family != AF_UNIX) {
33+
freeaddrinfo(c->res);
34+
} else {
35+
m_free(c->res);
36+
}
3237
}
3338
m_free(c->remotehost);
3439
m_free(c->remoteport);
@@ -59,6 +64,7 @@ static void connect_try_next(struct dropbear_progress_connection *c) {
5964
int err;
6065
int res = 0;
6166
int fastopen = 0;
67+
int retry_errno = EINPROGRESS;
6268
#if DROPBEAR_CLIENT_TCP_FAST_OPEN
6369
struct msghdr message;
6470
#endif
@@ -72,6 +78,11 @@ static void connect_try_next(struct dropbear_progress_connection *c) {
7278
continue;
7379
}
7480

81+
/* According to the connect(2) manpage it should be testing EAGAIN
82+
* rather than EINPROGRESS for unix sockets.
83+
*/
84+
retry_errno = r->ai_family == AF_UNIX ? EAGAIN : EINPROGRESS;
85+
7586
if (c->bind_address || c->bind_port) {
7687
/* bind to a source port/address */
7788
struct addrinfo hints;
@@ -116,7 +127,7 @@ static void connect_try_next(struct dropbear_progress_connection *c) {
116127
setnonblocking(c->sock);
117128

118129
#if DROPBEAR_CLIENT_TCP_FAST_OPEN
119-
fastopen = (c->writequeue != NULL);
130+
fastopen = (c->writequeue != NULL && r->ai_family != AF_UNIX);
120131

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

156-
if (res < 0 && errno != EINPROGRESS) {
167+
if (res < 0 && errno != retry_errno) {
157168
/* failure */
158169
m_free(c->errstring);
159170
c->errstring = m_strdup(strerror(errno));
@@ -225,6 +236,58 @@ struct dropbear_progress_connection *connect_remote(const char* remotehost, cons
225236
return c;
226237
}
227238

239+
240+
/* Connect to stream local socket. */
241+
struct dropbear_progress_connection *connect_streamlocal(const char* localpath,
242+
connect_callback cb, void* cb_data, enum dropbear_prio prio)
243+
{
244+
struct dropbear_progress_connection *c = NULL;
245+
struct sockaddr_un *sunaddr;
246+
247+
c = m_malloc(sizeof(*c));
248+
c->remotehost = m_strdup(localpath);
249+
c->remoteport = NULL;
250+
c->sock = -1;
251+
c->cb = cb;
252+
c->cb_data = cb_data;
253+
c->prio = prio;
254+
255+
list_append(&ses.conn_pending, c);
256+
257+
#if DROPBEAR_FUZZ
258+
if (fuzz.fuzzing) {
259+
c->errstring = m_strdup("fuzzing connect_streamlocal always fails");
260+
return c;
261+
}
262+
#endif
263+
264+
if (strlen(localpath) >= sizeof(sunaddr->sun_path)) {
265+
c->errstring = m_strdup("Stream path too long");
266+
TRACE(("localpath: %s is too long", localpath));
267+
return c;
268+
}
269+
270+
/*
271+
* Fake up a struct addrinfo for AF_UNIX connections.
272+
* remove_connect() must check ai_family
273+
* and use m_free() not freeaddirinfo() for AF_UNIX.
274+
*/
275+
c->res = m_malloc(sizeof(*c->res) + sizeof(*sunaddr));
276+
c->res->ai_addr = (struct sockaddr *)(c->res + 1);
277+
c->res->ai_addrlen = sizeof(*sunaddr);
278+
c->res->ai_family = AF_UNIX;
279+
c->res->ai_socktype = SOCK_STREAM;
280+
c->res->ai_protocol = PF_UNSPEC;
281+
sunaddr = (struct sockaddr_un *)c->res->ai_addr;
282+
sunaddr->sun_family = AF_UNIX;
283+
strlcpy(sunaddr->sun_path, localpath, sizeof(sunaddr->sun_path));
284+
285+
/* Copy to target iter */
286+
c->res_iter = c->res;
287+
288+
return c;
289+
}
290+
228291
void remove_connect_pending() {
229292
while (ses.conn_pending.first) {
230293
struct dropbear_progress_connection *c = ses.conn_pending.first->item;

src/netio.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ struct dropbear_progress_connection * connect_remote (const char* remotehost, co
3232
connect_callback cb, void *cb_data, const char* bind_address, const char* bind_port,
3333
enum dropbear_prio prio);
3434

35+
/* Connect to local stream, always returns a progress connection, if it fails it will call the callback at a later point */
36+
struct dropbear_progress_connection * connect_streamlocal (const char* localpath,
37+
connect_callback cb, void *cb_data,
38+
enum dropbear_prio prio);
39+
3540
/* Sets up for select() */
3641
void set_connect_fds(fd_set *writefd);
3742
/* Handles ready sockets after select() */

src/svr-session.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ static const struct ChanType *svr_chantypes[] = {
7575
&svrchansess,
7676
#if DROPBEAR_SVR_LOCALTCPFWD
7777
&svr_chan_tcpdirect,
78+
#endif
79+
#if DROPBEAR_SVR_LOCALSTREAMFWD
80+
&svr_chan_streamlocal,
7881
#endif
7982
NULL /* Null termination is mandatory. */
8083
};

src/svr-tcpfwd.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ void recv_msg_global_request_remotetcp() {
5656
static int svr_cancelremotetcp(void);
5757
static int svr_remotetcpreq(int *allocated_listen_port);
5858
static int newtcpdirect(struct Channel * channel);
59+
static int newstreamlocal(struct Channel * channel);
5960

6061
#if DROPBEAR_SVR_REMOTETCPFWD
6162
static const struct ChanType svr_chan_tcpremote = {
@@ -309,3 +310,57 @@ static int newtcpdirect(struct Channel * channel) {
309310
}
310311

311312
#endif /* DROPBEAR_SVR_LOCALTCPFWD */
313+
314+
315+
#if DROPBEAR_SVR_LOCALSTREAMFWD
316+
317+
const struct ChanType svr_chan_streamlocal = {
318+
"direct-streamlocal@openssh.com",
319+
newstreamlocal, /* init */
320+
NULL, /* checkclose */
321+
NULL, /* reqhandler */
322+
NULL, /* closehandler */
323+
NULL /* cleanup */
324+
};
325+
326+
/* Called upon creating a new stream local channel (ie we connect out to an
327+
* address */
328+
static int newstreamlocal(struct Channel * channel) {
329+
330+
/*
331+
https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL#rev1.30
332+
333+
byte SSH_MSG_CHANNEL_OPEN
334+
string "direct-streamlocal@openssh.com"
335+
uint32 sender channel
336+
uint32 initial window size
337+
uint32 maximum packet size
338+
string socket path
339+
string reserved
340+
uint32 reserved
341+
*/
342+
343+
char* destsocket = NULL;
344+
unsigned int len;
345+
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
346+
347+
TRACE(("streamlocal channel %d", channel->index))
348+
349+
destsocket = buf_getstring(ses.payload, &len);
350+
if (len > MAX_HOST_LEN) {
351+
TRACE(("leave streamlocal: destsocket too long"))
352+
goto out;
353+
}
354+
355+
channel->conn_pending = connect_streamlocal(destsocket, channel_connect_done,
356+
channel, DROPBEAR_PRIO_NORMAL);
357+
358+
err = SSH_OPEN_IN_PROGRESS;
359+
360+
out:
361+
m_free(destsocket);
362+
TRACE(("leave streamlocal: err %d", err))
363+
return err;
364+
}
365+
366+
#endif /* DROPBEAR_SVR_LOCALSTREAMFWD */

src/tcpfwd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ void recv_msg_global_request_remotetcp(void);
6363

6464
extern const struct ChanType svr_chan_tcpdirect;
6565

66+
extern const struct ChanType svr_chan_streamlocal;
67+
6668
/* Client */
6769
void setup_localtcp(void);
6870
void setup_remotetcp(void);

0 commit comments

Comments
 (0)