1 /* SPDX-License-Identifier: BSD-3-Clause */
3 * Copyright (c) 1995 Danny Gasparovski.
9 insque(void *a
, void *b
)
11 register struct quehead
*element
= (struct quehead
*) a
;
12 register struct quehead
*head
= (struct quehead
*) b
;
13 element
->qh_link
= head
->qh_link
;
14 head
->qh_link
= (struct quehead
*)element
;
15 element
->qh_rlink
= (struct quehead
*)head
;
16 ((struct quehead
*)(element
->qh_link
))->qh_rlink
17 = (struct quehead
*)element
;
23 register struct quehead
*element
= (struct quehead
*) a
;
24 ((struct quehead
*)(element
->qh_link
))->qh_rlink
= element
->qh_rlink
;
25 ((struct quehead
*)(element
->qh_rlink
))->qh_link
= element
->qh_link
;
26 element
->qh_rlink
= NULL
;
31 add_guestfwd(struct gfwd_list
**ex_ptr
,
32 SlirpWriteCb write_cb
, void *opaque
,
33 struct in_addr addr
, int port
)
35 struct gfwd_list
*f
= g_new0(struct gfwd_list
, 1);
37 f
->write_cb
= write_cb
;
48 add_exec(struct gfwd_list
**ex_ptr
, const char *cmdline
,
49 struct in_addr addr
, int port
)
51 struct gfwd_list
*f
= add_guestfwd(ex_ptr
, NULL
, NULL
, addr
, port
);
53 f
->ex_exec
= g_strdup(cmdline
);
59 slirp_socketpair_with_oob(int sv
[2])
61 struct sockaddr_in addr
= {
62 .sin_family
= AF_INET
,
64 .sin_addr
.s_addr
= INADDR_ANY
,
66 socklen_t addrlen
= sizeof(addr
);
70 s
= slirp_socket(AF_INET
, SOCK_STREAM
, 0);
71 if (s
< 0 || bind(s
, (struct sockaddr
*)&addr
, addrlen
) < 0 ||
73 getsockname(s
, (struct sockaddr
*)&addr
, &addrlen
) < 0) {
77 sv
[1] = slirp_socket(AF_INET
, SOCK_STREAM
, 0);
82 * This connect won't block because we've already listen()ed on
83 * the server end (even though we won't accept() the connection
87 ret
= connect(sv
[1], (struct sockaddr
*)&addr
, addrlen
);
88 } while (ret
< 0 && errno
== EINTR
);
94 sv
[0] = accept(s
, (struct sockaddr
*)&addr
, &addrlen
);
95 } while (sv
[0] < 0 && errno
== EINTR
);
104 g_critical("slirp_socketpair(): %s", strerror(errno
));
115 fork_exec_child_setup(gpointer data
)
122 #pragma GCC diagnostic push
123 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
125 #if !GLIB_CHECK_VERSION(2, 58, 0)
126 typedef struct SlirpGSpawnFds
{
127 GSpawnChildSetupFunc child_setup
;
135 slirp_gspawn_fds_setup(gpointer user_data
)
137 SlirpGSpawnFds
*q
= (SlirpGSpawnFds
*)user_data
;
139 dup2(q
->stdin_fd
, 0);
140 dup2(q
->stdout_fd
, 1);
141 dup2(q
->stderr_fd
, 2);
142 q
->child_setup(q
->user_data
);
146 static inline gboolean
147 g_spawn_async_with_fds_slirp(const gchar
*working_directory
,
151 GSpawnChildSetupFunc child_setup
,
159 #if GLIB_CHECK_VERSION(2, 58, 0)
160 return g_spawn_async_with_fds(working_directory
, argv
, envp
, flags
,
161 child_setup
, user_data
,
162 child_pid
, stdin_fd
, stdout_fd
, stderr_fd
,
165 SlirpGSpawnFds setup
= {
166 .child_setup
= child_setup
,
167 .user_data
= user_data
,
168 .stdin_fd
= stdin_fd
,
169 .stdout_fd
= stdout_fd
,
170 .stderr_fd
= stderr_fd
,
173 return g_spawn_async(working_directory
, argv
, envp
, flags
,
174 slirp_gspawn_fds_setup
, &setup
,
179 #define g_spawn_async_with_fds(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) \
180 g_spawn_async_with_fds_slirp(wd, argv, env, f, c, d, p, ifd, ofd, efd, err)
182 #pragma GCC diagnostic pop
185 fork_exec(struct socket
*so
, const char *ex
)
191 DEBUG_CALL("fork_exec");
192 DEBUG_ARG("so = %p", so
);
193 DEBUG_ARG("ex = %p", ex
);
195 if (slirp_socketpair_with_oob(sp
) < 0) {
199 argv
= g_strsplit(ex
, " ", -1);
200 g_spawn_async_with_fds(NULL
/* cwd */,
204 fork_exec_child_setup
, NULL
/* data */,
205 NULL
/* child_pid */,
211 g_critical("fork_exec: %s", err
->message
);
220 slirp_socket_set_fast_reuse(so
->s
);
222 setsockopt(so
->s
, SOL_SOCKET
, SO_OOBINLINE
, &opt
, sizeof(int));
223 slirp_set_nonblock(so
->s
);
224 so
->slirp
->cb
->register_poll_fd(so
->s
, so
->slirp
->opaque
);
228 char *slirp_connection_info(Slirp
*slirp
)
230 GString
*str
= g_string_new(NULL
);
231 const char * const tcpstates
[] = {
232 [TCPS_CLOSED
] = "CLOSED",
233 [TCPS_LISTEN
] = "LISTEN",
234 [TCPS_SYN_SENT
] = "SYN_SENT",
235 [TCPS_SYN_RECEIVED
] = "SYN_RCVD",
236 [TCPS_ESTABLISHED
] = "ESTABLISHED",
237 [TCPS_CLOSE_WAIT
] = "CLOSE_WAIT",
238 [TCPS_FIN_WAIT_1
] = "FIN_WAIT_1",
239 [TCPS_CLOSING
] = "CLOSING",
240 [TCPS_LAST_ACK
] = "LAST_ACK",
241 [TCPS_FIN_WAIT_2
] = "FIN_WAIT_2",
242 [TCPS_TIME_WAIT
] = "TIME_WAIT",
244 struct in_addr dst_addr
;
245 struct sockaddr_in src
;
252 g_string_append_printf(str
,
253 " Protocol[State] FD Source Address Port "
254 "Dest. Address Port RecvQ SendQ\n");
258 for (so
= slirp
->tcb
.so_next
; so
!= &slirp
->tcb
; so
= so
->so_next
) {
259 if (so
->so_state
& SS_HOSTFWD
) {
260 state
= "HOST_FORWARD";
261 } else if (so
->so_tcpcb
) {
262 state
= tcpstates
[so
->so_tcpcb
->t_state
];
266 if (so
->so_state
& (SS_HOSTFWD
| SS_INCOMING
)) {
267 src_len
= sizeof(src
);
268 getsockname(so
->s
, (struct sockaddr
*)&src
, &src_len
);
269 dst_addr
= so
->so_laddr
;
270 dst_port
= so
->so_lport
;
272 src
.sin_addr
= so
->so_laddr
;
273 src
.sin_port
= so
->so_lport
;
274 dst_addr
= so
->so_faddr
;
275 dst_port
= so
->so_fport
;
277 snprintf(buf
, sizeof(buf
), " TCP[%s]", state
);
278 g_string_append_printf(str
, "%-19s %3d %15s %5d ", buf
, so
->s
,
279 src
.sin_addr
.s_addr
? inet_ntoa(src
.sin_addr
) : "*",
280 ntohs(src
.sin_port
));
281 g_string_append_printf(str
, "%15s %5d %5d %5d\n",
282 inet_ntoa(dst_addr
), ntohs(dst_port
),
283 so
->so_rcv
.sb_cc
, so
->so_snd
.sb_cc
);
286 for (so
= slirp
->udb
.so_next
; so
!= &slirp
->udb
; so
= so
->so_next
) {
287 if (so
->so_state
& SS_HOSTFWD
) {
288 snprintf(buf
, sizeof(buf
), " UDP[HOST_FORWARD]");
289 src_len
= sizeof(src
);
290 getsockname(so
->s
, (struct sockaddr
*)&src
, &src_len
);
291 dst_addr
= so
->so_laddr
;
292 dst_port
= so
->so_lport
;
294 snprintf(buf
, sizeof(buf
), " UDP[%d sec]",
295 (so
->so_expire
- curtime
) / 1000);
296 src
.sin_addr
= so
->so_laddr
;
297 src
.sin_port
= so
->so_lport
;
298 dst_addr
= so
->so_faddr
;
299 dst_port
= so
->so_fport
;
301 g_string_append_printf(str
, "%-19s %3d %15s %5d ", buf
, so
->s
,
302 src
.sin_addr
.s_addr
? inet_ntoa(src
.sin_addr
) : "*",
303 ntohs(src
.sin_port
));
304 g_string_append_printf(str
, "%15s %5d %5d %5d\n",
305 inet_ntoa(dst_addr
), ntohs(dst_port
),
306 so
->so_rcv
.sb_cc
, so
->so_snd
.sb_cc
);
309 for (so
= slirp
->icmp
.so_next
; so
!= &slirp
->icmp
; so
= so
->so_next
) {
310 snprintf(buf
, sizeof(buf
), " ICMP[%d sec]",
311 (so
->so_expire
- curtime
) / 1000);
312 src
.sin_addr
= so
->so_laddr
;
313 dst_addr
= so
->so_faddr
;
314 g_string_append_printf(str
, "%-19s %3d %15s - ", buf
, so
->s
,
315 src
.sin_addr
.s_addr
? inet_ntoa(src
.sin_addr
) : "*");
316 g_string_append_printf(str
, "%15s - %5d %5d\n", inet_ntoa(dst_addr
),
317 so
->so_rcv
.sb_cc
, so
->so_snd
.sb_cc
);
320 return g_string_free(str
, FALSE
);