@@ -28,7 +28,12 @@ struct dropbear_progress_connection {
2828Does not close sockets */
2929static 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+
228291void remove_connect_pending () {
229292 while (ses .conn_pending .first ) {
230293 struct dropbear_progress_connection * c = ses .conn_pending .first -> item ;
0 commit comments