]>
Commit | Line | Data |
---|---|---|
3e6d35e5 | 1 | /* SPDX-License-Identifier: BSD-3-Clause */ |
f0cbd3ec FB |
2 | /* |
3 | * Copyright (c) 1995 Danny Gasparovski. | |
5fafdf24 | 4 | * |
f0cbd3ec FB |
5 | * Please read the file COPYRIGHT for the |
6 | * terms and conditions of the copyright. | |
7 | */ | |
8 | ||
a9c94277 | 9 | #include "slirp.h" |
f0cbd3ec | 10 | |
f0cbd3ec | 11 | inline void |
511d2b14 | 12 | insque(void *a, void *b) |
f0cbd3ec FB |
13 | { |
14 | register struct quehead *element = (struct quehead *) a; | |
15 | register struct quehead *head = (struct quehead *) b; | |
16 | element->qh_link = head->qh_link; | |
17 | head->qh_link = (struct quehead *)element; | |
18 | element->qh_rlink = (struct quehead *)head; | |
19 | ((struct quehead *)(element->qh_link))->qh_rlink | |
20 | = (struct quehead *)element; | |
21 | } | |
22 | ||
23 | inline void | |
511d2b14 | 24 | remque(void *a) |
f0cbd3ec FB |
25 | { |
26 | register struct quehead *element = (struct quehead *) a; | |
27 | ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink; | |
28 | ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link; | |
29 | element->qh_rlink = NULL; | |
f0cbd3ec FB |
30 | } |
31 | ||
ffe02f55 | 32 | /* TODO: IPv6 */ |
44b4ff24 MAL |
33 | struct gfwd_list * |
34 | add_guestfwd(struct gfwd_list **ex_ptr, | |
35 | SlirpWriteCb write_cb, void *opaque, | |
a13a4126 | 36 | struct in_addr addr, int port) |
f0cbd3ec | 37 | { |
44b4ff24 | 38 | struct gfwd_list *f = g_new0(struct gfwd_list, 1); |
5fafdf24 | 39 | |
44b4ff24 MAL |
40 | f->write_cb = write_cb; |
41 | f->opaque = opaque; | |
42 | f->ex_fport = port; | |
43 | f->ex_addr = addr; | |
44 | f->ex_next = *ex_ptr; | |
45 | *ex_ptr = f; | |
46 | ||
47 | return f; | |
f0cbd3ec FB |
48 | } |
49 | ||
44b4ff24 MAL |
50 | struct gfwd_list * |
51 | add_exec(struct gfwd_list **ex_ptr, const char *cmdline, | |
52 | struct in_addr addr, int port) | |
53 | { | |
54 | struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port); | |
55 | ||
56 | f->ex_exec = g_strdup(cmdline); | |
57 | ||
58 | return f; | |
59 | } | |
f0cbd3ec | 60 | |
7f514092 MAL |
61 | static int |
62 | slirp_socketpair_with_oob(int sv[2]) | |
63 | { | |
64 | struct sockaddr_in addr = { | |
65 | .sin_family = AF_INET, | |
66 | .sin_port = 0, | |
67 | .sin_addr.s_addr = INADDR_ANY, | |
68 | }; | |
69 | socklen_t addrlen = sizeof(addr); | |
70 | int ret, s; | |
71 | ||
72 | sv[1] = -1; | |
707bd47e | 73 | s = slirp_socket(AF_INET, SOCK_STREAM, 0); |
7f514092 MAL |
74 | if (s < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 || |
75 | listen(s, 1) < 0 || | |
76 | getsockname(s, (struct sockaddr *)&addr, &addrlen) < 0) { | |
77 | goto err; | |
78 | } | |
79 | ||
707bd47e | 80 | sv[1] = slirp_socket(AF_INET, SOCK_STREAM, 0); |
7f514092 MAL |
81 | if (sv[1] < 0) { |
82 | goto err; | |
83 | } | |
84 | /* | |
85 | * This connect won't block because we've already listen()ed on | |
86 | * the server end (even though we won't accept() the connection | |
87 | * until later on). | |
88 | */ | |
89 | do { | |
90 | ret = connect(sv[1], (struct sockaddr *)&addr, addrlen); | |
91 | } while (ret < 0 && errno == EINTR); | |
92 | if (ret < 0) { | |
93 | goto err; | |
94 | } | |
95 | ||
96 | do { | |
97 | sv[0] = accept(s, (struct sockaddr *)&addr, &addrlen); | |
98 | } while (sv[0] < 0 && errno == EINTR); | |
99 | if (sv[0] < 0) { | |
100 | goto err; | |
101 | } | |
102 | ||
fdbfba8c | 103 | closesocket(s); |
7f514092 MAL |
104 | return 0; |
105 | ||
106 | err: | |
90dfa278 | 107 | g_critical("slirp_socketpair(): %s", strerror(errno)); |
7f514092 | 108 | if (s >= 0) { |
fdbfba8c | 109 | closesocket(s); |
7f514092 MAL |
110 | } |
111 | if (sv[1] >= 0) { | |
fdbfba8c | 112 | closesocket(sv[1]); |
7f514092 MAL |
113 | } |
114 | return -1; | |
115 | } | |
116 | ||
2bdb920e MAL |
117 | static void |
118 | fork_exec_child_setup(gpointer data) | |
119 | { | |
e589a442 | 120 | #ifndef _WIN32 |
2bdb920e | 121 | setsid(); |
e589a442 | 122 | #endif |
2bdb920e MAL |
123 | } |
124 | ||
4ffa6325 ST |
125 | #pragma GCC diagnostic push |
126 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" | |
127 | ||
128 | #if !GLIB_CHECK_VERSION(2, 58, 0) | |
129 | typedef struct SlirpGSpawnFds { | |
130 | GSpawnChildSetupFunc child_setup; | |
131 | gpointer user_data; | |
132 | gint stdin_fd; | |
133 | gint stdout_fd; | |
134 | gint stderr_fd; | |
135 | } SlirpGSpawnFds; | |
136 | ||
137 | static inline void | |
138 | slirp_gspawn_fds_setup(gpointer user_data) | |
139 | { | |
140 | SlirpGSpawnFds *q = (SlirpGSpawnFds *)user_data; | |
141 | ||
142 | dup2(q->stdin_fd, 0); | |
143 | dup2(q->stdout_fd, 1); | |
144 | dup2(q->stderr_fd, 2); | |
145 | q->child_setup(q->user_data); | |
146 | } | |
147 | #endif | |
148 | ||
149 | static inline gboolean | |
150 | g_spawn_async_with_fds_slirp(const gchar *working_directory, | |
151 | gchar **argv, | |
152 | gchar **envp, | |
153 | GSpawnFlags flags, | |
154 | GSpawnChildSetupFunc child_setup, | |
155 | gpointer user_data, | |
156 | GPid *child_pid, | |
157 | gint stdin_fd, | |
158 | gint stdout_fd, | |
159 | gint stderr_fd, | |
160 | GError **error) | |
161 | { | |
162 | #if GLIB_CHECK_VERSION(2, 58, 0) | |
163 | return g_spawn_async_with_fds(working_directory, argv, envp, flags, | |
164 | child_setup, user_data, | |
165 | child_pid, stdin_fd, stdout_fd, stderr_fd, | |
166 | error); | |
167 | #else | |
168 | SlirpGSpawnFds setup = { | |
169 | .child_setup = child_setup, | |
170 | .user_data = user_data, | |
171 | .stdin_fd = stdin_fd, | |
172 | .stdout_fd = stdout_fd, | |
173 | .stderr_fd = stderr_fd, | |
174 | }; | |
175 | ||
176 | return g_spawn_async(working_directory, argv, envp, flags, | |
177 | slirp_gspawn_fds_setup, &setup, | |
178 | child_pid, error); | |
179 | #endif | |
180 | } | |
181 | ||
182 | #define g_spawn_async_with_fds(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) \ | |
183 | g_spawn_async_with_fds_slirp(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) | |
184 | ||
185 | #pragma GCC diagnostic pop | |
186 | ||
f0cbd3ec | 187 | int |
43bc7340 | 188 | fork_exec(struct socket *so, const char *ex) |
f0cbd3ec | 189 | { |
2bdb920e MAL |
190 | GError *err = NULL; |
191 | char **argv; | |
192 | int opt, sp[2]; | |
5fafdf24 | 193 | |
2bdb920e MAL |
194 | DEBUG_CALL("fork_exec"); |
195 | DEBUG_ARG("so = %p", so); | |
196 | DEBUG_ARG("ex = %p", ex); | |
43bc7340 | 197 | |
7f514092 | 198 | if (slirp_socketpair_with_oob(sp) < 0) { |
43bc7340 MAL |
199 | return 0; |
200 | } | |
5fafdf24 | 201 | |
2bdb920e MAL |
202 | argv = g_strsplit(ex, " ", -1); |
203 | g_spawn_async_with_fds(NULL /* cwd */, | |
204 | argv, | |
205 | NULL /* env */, | |
206 | G_SPAWN_SEARCH_PATH, | |
207 | fork_exec_child_setup, NULL /* data */, | |
208 | NULL /* child_pid */, | |
209 | sp[1], sp[1], sp[1], | |
210 | &err); | |
211 | g_strfreev(argv); | |
212 | ||
213 | if (err) { | |
6b744ea4 | 214 | g_critical("fork_exec: %s", err->message); |
2bdb920e | 215 | g_error_free(err); |
fdbfba8c MAL |
216 | closesocket(sp[0]); |
217 | closesocket(sp[1]); | |
2bdb920e MAL |
218 | return 0; |
219 | } | |
220 | ||
221 | so->s = sp[0]; | |
fdbfba8c | 222 | closesocket(sp[1]); |
707bd47e | 223 | slirp_socket_set_fast_reuse(so->s); |
2bdb920e | 224 | opt = 1; |
fdbfba8c | 225 | setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); |
848c7092 | 226 | slirp_set_nonblock(so->s); |
3e0fad3a | 227 | so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque); |
2bdb920e | 228 | return 1; |
f0cbd3ec | 229 | } |
f0cbd3ec | 230 | |
b7f43bf2 | 231 | char *slirp_connection_info(Slirp *slirp) |
6dbe553f | 232 | { |
b7f43bf2 | 233 | GString *str = g_string_new(NULL); |
6dbe553f JK |
234 | const char * const tcpstates[] = { |
235 | [TCPS_CLOSED] = "CLOSED", | |
236 | [TCPS_LISTEN] = "LISTEN", | |
237 | [TCPS_SYN_SENT] = "SYN_SENT", | |
238 | [TCPS_SYN_RECEIVED] = "SYN_RCVD", | |
239 | [TCPS_ESTABLISHED] = "ESTABLISHED", | |
240 | [TCPS_CLOSE_WAIT] = "CLOSE_WAIT", | |
241 | [TCPS_FIN_WAIT_1] = "FIN_WAIT_1", | |
242 | [TCPS_CLOSING] = "CLOSING", | |
243 | [TCPS_LAST_ACK] = "LAST_ACK", | |
244 | [TCPS_FIN_WAIT_2] = "FIN_WAIT_2", | |
245 | [TCPS_TIME_WAIT] = "TIME_WAIT", | |
246 | }; | |
247 | struct in_addr dst_addr; | |
248 | struct sockaddr_in src; | |
249 | socklen_t src_len; | |
250 | uint16_t dst_port; | |
251 | struct socket *so; | |
252 | const char *state; | |
253 | char buf[20]; | |
6dbe553f | 254 | |
b7f43bf2 MAL |
255 | g_string_append_printf(str, |
256 | " Protocol[State] FD Source Address Port " | |
257 | "Dest. Address Port RecvQ SendQ\n"); | |
6dbe553f | 258 | |
ffe02f55 ST |
259 | /* TODO: IPv6 */ |
260 | ||
460fec67 | 261 | for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) { |
6dbe553f JK |
262 | if (so->so_state & SS_HOSTFWD) { |
263 | state = "HOST_FORWARD"; | |
264 | } else if (so->so_tcpcb) { | |
265 | state = tcpstates[so->so_tcpcb->t_state]; | |
266 | } else { | |
267 | state = "NONE"; | |
268 | } | |
269 | if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) { | |
270 | src_len = sizeof(src); | |
271 | getsockname(so->s, (struct sockaddr *)&src, &src_len); | |
272 | dst_addr = so->so_laddr; | |
273 | dst_port = so->so_lport; | |
274 | } else { | |
275 | src.sin_addr = so->so_laddr; | |
276 | src.sin_port = so->so_lport; | |
277 | dst_addr = so->so_faddr; | |
278 | dst_port = so->so_fport; | |
279 | } | |
f293d8b1 | 280 | snprintf(buf, sizeof(buf), " TCP[%s]", state); |
b7f43bf2 | 281 | g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s, |
6dbe553f JK |
282 | src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*", |
283 | ntohs(src.sin_port)); | |
b7f43bf2 | 284 | g_string_append_printf(str, "%15s %5d %5d %5d\n", |
6dbe553f JK |
285 | inet_ntoa(dst_addr), ntohs(dst_port), |
286 | so->so_rcv.sb_cc, so->so_snd.sb_cc); | |
287 | } | |
288 | ||
460fec67 | 289 | for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) { |
6dbe553f | 290 | if (so->so_state & SS_HOSTFWD) { |
f293d8b1 | 291 | snprintf(buf, sizeof(buf), " UDP[HOST_FORWARD]"); |
6dbe553f JK |
292 | src_len = sizeof(src); |
293 | getsockname(so->s, (struct sockaddr *)&src, &src_len); | |
294 | dst_addr = so->so_laddr; | |
295 | dst_port = so->so_lport; | |
296 | } else { | |
f293d8b1 | 297 | snprintf(buf, sizeof(buf), " UDP[%d sec]", |
6dbe553f JK |
298 | (so->so_expire - curtime) / 1000); |
299 | src.sin_addr = so->so_laddr; | |
300 | src.sin_port = so->so_lport; | |
301 | dst_addr = so->so_faddr; | |
302 | dst_port = so->so_fport; | |
303 | } | |
b7f43bf2 | 304 | g_string_append_printf(str, "%-19s %3d %15s %5d ", buf, so->s, |
6dbe553f JK |
305 | src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*", |
306 | ntohs(src.sin_port)); | |
b7f43bf2 | 307 | g_string_append_printf(str, "%15s %5d %5d %5d\n", |
6dbe553f JK |
308 | inet_ntoa(dst_addr), ntohs(dst_port), |
309 | so->so_rcv.sb_cc, so->so_snd.sb_cc); | |
310 | } | |
e6d43cfb JK |
311 | |
312 | for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) { | |
f293d8b1 | 313 | snprintf(buf, sizeof(buf), " ICMP[%d sec]", |
e6d43cfb JK |
314 | (so->so_expire - curtime) / 1000); |
315 | src.sin_addr = so->so_laddr; | |
316 | dst_addr = so->so_faddr; | |
b7f43bf2 | 317 | g_string_append_printf(str, "%-19s %3d %15s - ", buf, so->s, |
e6d43cfb | 318 | src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*"); |
b7f43bf2 | 319 | g_string_append_printf(str, "%15s - %5d %5d\n", inet_ntoa(dst_addr), |
e6d43cfb JK |
320 | so->so_rcv.sb_cc, so->so_snd.sb_cc); |
321 | } | |
b7f43bf2 MAL |
322 | |
323 | return g_string_free(str, FALSE); | |
6dbe553f | 324 | } |