]>
Commit | Line | Data |
---|---|---|
3e6d35e5 | 1 | /* SPDX-License-Identifier: BSD-3-Clause */ |
f0cbd3ec FB |
2 | /* |
3 | * Copyright (c) 1995 Danny Gasparovski. | |
f0cbd3ec FB |
4 | */ |
5 | ||
a9c94277 | 6 | #include "slirp.h" |
f0cbd3ec | 7 | #include "ip_icmp.h" |
ec530c81 FB |
8 | #ifdef __sun__ |
9 | #include <sys/filio.h> | |
10 | #endif | |
f0cbd3ec | 11 | |
9634d903 BS |
12 | static void sofcantrcvmore(struct socket *so); |
13 | static void sofcantsendmore(struct socket *so); | |
14 | ||
8a87f121 GS |
15 | struct socket *solookup(struct socket **last, struct socket *head, |
16 | struct sockaddr_storage *lhost, struct sockaddr_storage *fhost) | |
f0cbd3ec | 17 | { |
a5fd24aa | 18 | struct socket *so = *last; |
5fafdf24 | 19 | |
a5fd24aa | 20 | /* Optimisation */ |
8a87f121 GS |
21 | if (so != head && sockaddr_equal(&(so->lhost.ss), lhost) |
22 | && (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) { | |
a5fd24aa GS |
23 | return so; |
24 | } | |
5fafdf24 | 25 | |
a5fd24aa | 26 | for (so = head->so_next; so != head; so = so->so_next) { |
8a87f121 GS |
27 | if (sockaddr_equal(&(so->lhost.ss), lhost) |
28 | && (!fhost || sockaddr_equal(&so->fhost.ss, fhost))) { | |
a5fd24aa GS |
29 | *last = so; |
30 | return so; | |
31 | } | |
32 | } | |
5fafdf24 | 33 | |
a5fd24aa | 34 | return (struct socket *)NULL; |
f0cbd3ec FB |
35 | } |
36 | ||
37 | /* | |
38 | * Create a new socket, initialise the fields | |
39 | * It is the responsibility of the caller to | |
40 | * insque() it into the correct linked-list | |
41 | */ | |
42 | struct socket * | |
460fec67 | 43 | socreate(Slirp *slirp) |
f0cbd3ec | 44 | { |
84ec9bfa | 45 | struct socket *so = g_new(struct socket, 1); |
5fafdf24 | 46 | |
f0cbd3ec FB |
47 | memset(so, 0, sizeof(struct socket)); |
48 | so->so_state = SS_NOFDREF; | |
49 | so->s = -1; | |
460fec67 | 50 | so->slirp = slirp; |
7bd43ec2 | 51 | so->pollfds_idx = -1; |
84ec9bfa PM |
52 | |
53 | return so; | |
f0cbd3ec FB |
54 | } |
55 | ||
1201d308 ST |
56 | /* |
57 | * Remove references to so from the given message queue. | |
58 | */ | |
59 | static void | |
60 | soqfree(struct socket *so, struct quehead *qh) | |
61 | { | |
62 | struct mbuf *ifq; | |
63 | ||
64 | for (ifq = (struct mbuf *) qh->qh_link; | |
65 | (struct quehead *) ifq != qh; | |
66 | ifq = ifq->ifq_next) { | |
67 | if (ifq->ifq_so == so) { | |
68 | struct mbuf *ifm; | |
69 | ifq->ifq_so = NULL; | |
70 | for (ifm = ifq->ifs_next; ifm != ifq; ifm = ifm->ifs_next) { | |
71 | ifm->ifq_so = NULL; | |
72 | } | |
73 | } | |
74 | } | |
75 | } | |
76 | ||
f0cbd3ec FB |
77 | /* |
78 | * remque and free a socket, clobber cache | |
79 | */ | |
80 | void | |
511d2b14 | 81 | sofree(struct socket *so) |
f0cbd3ec | 82 | { |
460fec67 | 83 | Slirp *slirp = so->slirp; |
ea64d5f0 | 84 | |
1201d308 ST |
85 | soqfree(so, &slirp->if_fastq); |
86 | soqfree(so, &slirp->if_batchq); | |
460fec67 | 87 | |
460fec67 JK |
88 | if (so == slirp->tcp_last_so) { |
89 | slirp->tcp_last_so = &slirp->tcb; | |
90 | } else if (so == slirp->udp_last_so) { | |
91 | slirp->udp_last_so = &slirp->udb; | |
e6d43cfb JK |
92 | } else if (so == slirp->icmp_last_so) { |
93 | slirp->icmp_last_so = &slirp->icmp; | |
460fec67 | 94 | } |
f0cbd3ec | 95 | m_free(so->so_m); |
5fafdf24 TS |
96 | |
97 | if(so->so_next && so->so_prev) | |
f0cbd3ec FB |
98 | remque(so); /* crashes if so is not in a queue */ |
99 | ||
7d824696 MAL |
100 | if (so->so_tcpcb) { |
101 | free(so->so_tcpcb); | |
102 | } | |
84ec9bfa | 103 | g_free(so); |
f0cbd3ec FB |
104 | } |
105 | ||
e1c5a2b3 | 106 | size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np) |
f0cbd3ec | 107 | { |
e1c5a2b3 | 108 | int n, lss, total; |
f0cbd3ec FB |
109 | struct sbuf *sb = &so->so_snd; |
110 | int len = sb->sb_datalen - sb->sb_cc; | |
f0cbd3ec | 111 | int mss = so->so_tcpcb->t_maxseg; |
5fafdf24 | 112 | |
e1c5a2b3 | 113 | DEBUG_CALL("sopreprbuf"); |
ecc804ca | 114 | DEBUG_ARG("so = %p", so); |
5fafdf24 | 115 | |
e1c5a2b3 AL |
116 | if (len <= 0) |
117 | return 0; | |
118 | ||
f0cbd3ec | 119 | iov[0].iov_base = sb->sb_wptr; |
66029f6a BS |
120 | iov[1].iov_base = NULL; |
121 | iov[1].iov_len = 0; | |
f0cbd3ec FB |
122 | if (sb->sb_wptr < sb->sb_rptr) { |
123 | iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; | |
124 | /* Should never succeed, but... */ | |
125 | if (iov[0].iov_len > len) | |
126 | iov[0].iov_len = len; | |
127 | if (iov[0].iov_len > mss) | |
128 | iov[0].iov_len -= iov[0].iov_len%mss; | |
129 | n = 1; | |
130 | } else { | |
131 | iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr; | |
132 | /* Should never succeed, but... */ | |
133 | if (iov[0].iov_len > len) iov[0].iov_len = len; | |
134 | len -= iov[0].iov_len; | |
135 | if (len) { | |
136 | iov[1].iov_base = sb->sb_data; | |
137 | iov[1].iov_len = sb->sb_rptr - sb->sb_data; | |
138 | if(iov[1].iov_len > len) | |
139 | iov[1].iov_len = len; | |
140 | total = iov[0].iov_len + iov[1].iov_len; | |
141 | if (total > mss) { | |
142 | lss = total%mss; | |
143 | if (iov[1].iov_len > lss) { | |
144 | iov[1].iov_len -= lss; | |
145 | n = 2; | |
146 | } else { | |
147 | lss -= iov[1].iov_len; | |
148 | iov[0].iov_len -= lss; | |
149 | n = 1; | |
150 | } | |
151 | } else | |
152 | n = 2; | |
153 | } else { | |
154 | if (iov[0].iov_len > mss) | |
155 | iov[0].iov_len -= iov[0].iov_len%mss; | |
156 | n = 1; | |
157 | } | |
158 | } | |
e1c5a2b3 AL |
159 | if (np) |
160 | *np = n; | |
161 | ||
162 | return iov[0].iov_len + (n - 1) * iov[1].iov_len; | |
163 | } | |
164 | ||
165 | /* | |
166 | * Read from so's socket into sb_snd, updating all relevant sbuf fields | |
167 | * NOTE: This will only be called if it is select()ed for reading, so | |
168 | * a read() of 0 (or less) means it's disconnected | |
169 | */ | |
170 | int | |
511d2b14 | 171 | soread(struct socket *so) |
e1c5a2b3 AL |
172 | { |
173 | int n, nn; | |
6fabae61 | 174 | size_t buf_len; |
e1c5a2b3 AL |
175 | struct sbuf *sb = &so->so_snd; |
176 | struct iovec iov[2]; | |
177 | ||
178 | DEBUG_CALL("soread"); | |
ecc804ca | 179 | DEBUG_ARG("so = %p", so); |
e1c5a2b3 AL |
180 | |
181 | /* | |
182 | * No need to check if there's enough room to read. | |
183 | * soread wouldn't have been called if there weren't | |
184 | */ | |
6fabae61 DDAG |
185 | buf_len = sopreprbuf(so, iov, &n); |
186 | assert(buf_len != 0); | |
5fafdf24 | 187 | |
fdbfba8c | 188 | nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0); |
f0cbd3ec FB |
189 | if (nn <= 0) { |
190 | if (nn < 0 && (errno == EINTR || errno == EAGAIN)) | |
191 | return 0; | |
192 | else { | |
27d92ebc | 193 | int err; |
93a972f8 GG |
194 | socklen_t elen = sizeof err; |
195 | struct sockaddr_storage addr; | |
196 | struct sockaddr *paddr = (struct sockaddr *) &addr; | |
197 | socklen_t alen = sizeof addr; | |
27d92ebc EI |
198 | |
199 | err = errno; | |
200 | if (nn == 0) { | |
93a972f8 GG |
201 | if (getpeername(so->s, paddr, &alen) < 0) { |
202 | err = errno; | |
203 | } else { | |
fdbfba8c | 204 | getsockopt(so->s, SOL_SOCKET, SO_ERROR, |
93a972f8 GG |
205 | &err, &elen); |
206 | } | |
27d92ebc EI |
207 | } |
208 | ||
226ea7a9 MAL |
209 | DEBUG_MISC(" --- soread() disconnected, nn = %d, errno = %d-%s", |
210 | nn, errno,strerror(errno)); | |
f0cbd3ec | 211 | sofcantrcvmore(so); |
27d92ebc | 212 | |
6625d83a | 213 | if (err == ECONNRESET || err == ECONNREFUSED |
27d92ebc EI |
214 | || err == ENOTCONN || err == EPIPE) { |
215 | tcp_drop(sototcpcb(so), err); | |
216 | } else { | |
217 | tcp_sockclosed(sototcpcb(so)); | |
218 | } | |
f0cbd3ec FB |
219 | return -1; |
220 | } | |
221 | } | |
5fafdf24 | 222 | |
f0cbd3ec FB |
223 | /* |
224 | * If there was no error, try and read the second time round | |
225 | * We read again if n = 2 (ie, there's another part of the buffer) | |
226 | * and we read as much as we could in the first read | |
227 | * We don't test for <= 0 this time, because there legitimately | |
228 | * might not be any more data (since the socket is non-blocking), | |
229 | * a close will be detected on next iteration. | |
cb8d4c8f | 230 | * A return of -1 won't (shouldn't) happen, since it didn't happen above |
f0cbd3ec | 231 | */ |
17444c9c FB |
232 | if (n == 2 && nn == iov[0].iov_len) { |
233 | int ret; | |
fdbfba8c | 234 | ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0); |
17444c9c FB |
235 | if (ret > 0) |
236 | nn += ret; | |
237 | } | |
5fafdf24 | 238 | |
226ea7a9 | 239 | DEBUG_MISC(" ... read nn = %d bytes", nn); |
5fafdf24 | 240 | |
f0cbd3ec FB |
241 | /* Update fields */ |
242 | sb->sb_cc += nn; | |
243 | sb->sb_wptr += nn; | |
244 | if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) | |
245 | sb->sb_wptr -= sb->sb_datalen; | |
246 | return nn; | |
247 | } | |
5fafdf24 | 248 | |
e1c5a2b3 AL |
249 | int soreadbuf(struct socket *so, const char *buf, int size) |
250 | { | |
251 | int n, nn, copy = size; | |
252 | struct sbuf *sb = &so->so_snd; | |
253 | struct iovec iov[2]; | |
254 | ||
255 | DEBUG_CALL("soreadbuf"); | |
ecc804ca | 256 | DEBUG_ARG("so = %p", so); |
e1c5a2b3 AL |
257 | |
258 | /* | |
259 | * No need to check if there's enough room to read. | |
260 | * soread wouldn't have been called if there weren't | |
261 | */ | |
6fabae61 | 262 | assert(size > 0); |
e1c5a2b3 AL |
263 | if (sopreprbuf(so, iov, &n) < size) |
264 | goto err; | |
265 | ||
266 | nn = MIN(iov[0].iov_len, copy); | |
267 | memcpy(iov[0].iov_base, buf, nn); | |
268 | ||
269 | copy -= nn; | |
270 | buf += nn; | |
271 | ||
272 | if (copy == 0) | |
273 | goto done; | |
274 | ||
275 | memcpy(iov[1].iov_base, buf, copy); | |
276 | ||
277 | done: | |
278 | /* Update fields */ | |
279 | sb->sb_cc += size; | |
280 | sb->sb_wptr += size; | |
281 | if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) | |
282 | sb->sb_wptr -= sb->sb_datalen; | |
283 | return size; | |
284 | err: | |
285 | ||
286 | sofcantrcvmore(so); | |
287 | tcp_sockclosed(sototcpcb(so)); | |
b0866f0c | 288 | g_critical("soreadbuf buffer too small"); |
e1c5a2b3 AL |
289 | return -1; |
290 | } | |
291 | ||
f0cbd3ec FB |
292 | /* |
293 | * Get urgent data | |
5fafdf24 | 294 | * |
f0cbd3ec FB |
295 | * When the socket is created, we set it SO_OOBINLINE, |
296 | * so when OOB data arrives, we soread() it and everything | |
297 | * in the send buffer is sent as urgent data | |
298 | */ | |
bfb1ac14 | 299 | int |
511d2b14 | 300 | sorecvoob(struct socket *so) |
f0cbd3ec FB |
301 | { |
302 | struct tcpcb *tp = sototcpcb(so); | |
bfb1ac14 | 303 | int ret; |
f0cbd3ec FB |
304 | |
305 | DEBUG_CALL("sorecvoob"); | |
ecc804ca | 306 | DEBUG_ARG("so = %p", so); |
5fafdf24 | 307 | |
f0cbd3ec FB |
308 | /* |
309 | * We take a guess at how much urgent data has arrived. | |
310 | * In most situations, when urgent data arrives, the next | |
311 | * read() should get all the urgent data. This guess will | |
312 | * be wrong however if more data arrives just after the | |
5fafdf24 | 313 | * urgent data, or the read() doesn't return all the |
f0cbd3ec FB |
314 | * urgent data. |
315 | */ | |
bfb1ac14 SL |
316 | ret = soread(so); |
317 | if (ret > 0) { | |
318 | tp->snd_up = tp->snd_una + so->so_snd.sb_cc; | |
319 | tp->t_force = 1; | |
320 | tcp_output(tp); | |
321 | tp->t_force = 0; | |
322 | } | |
323 | ||
324 | return ret; | |
f0cbd3ec FB |
325 | } |
326 | ||
327 | /* | |
328 | * Send urgent data | |
329 | * There's a lot duplicated code here, but... | |
330 | */ | |
331 | int | |
511d2b14 | 332 | sosendoob(struct socket *so) |
f0cbd3ec FB |
333 | { |
334 | struct sbuf *sb = &so->so_rcv; | |
335 | char buff[2048]; /* XXX Shouldn't be sending more oob data than this */ | |
5fafdf24 | 336 | |
c7950fb3 | 337 | int n; |
5fafdf24 | 338 | |
f0cbd3ec | 339 | DEBUG_CALL("sosendoob"); |
ecc804ca | 340 | DEBUG_ARG("so = %p", so); |
f0cbd3ec | 341 | DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc); |
5fafdf24 | 342 | |
f0cbd3ec FB |
343 | if (so->so_urgc > 2048) |
344 | so->so_urgc = 2048; /* XXXX */ | |
5fafdf24 | 345 | |
f0cbd3ec FB |
346 | if (sb->sb_rptr < sb->sb_wptr) { |
347 | /* We can send it directly */ | |
e1c5a2b3 | 348 | n = slirp_send(so, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ |
f0cbd3ec | 349 | } else { |
5fafdf24 | 350 | /* |
f0cbd3ec FB |
351 | * Since there's no sendv or sendtov like writev, |
352 | * we must copy all data to a linear buffer then | |
353 | * send it all | |
354 | */ | |
0b466065 | 355 | uint32_t urgc = so->so_urgc; |
c7950fb3 | 356 | int len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; |
0b466065 PM |
357 | if (len > urgc) { |
358 | len = urgc; | |
359 | } | |
f0cbd3ec | 360 | memcpy(buff, sb->sb_rptr, len); |
0b466065 PM |
361 | urgc -= len; |
362 | if (urgc) { | |
f0cbd3ec | 363 | n = sb->sb_wptr - sb->sb_data; |
0b466065 PM |
364 | if (n > urgc) { |
365 | n = urgc; | |
366 | } | |
f0cbd3ec | 367 | memcpy((buff + len), sb->sb_data, n); |
f0cbd3ec FB |
368 | len += n; |
369 | } | |
e1c5a2b3 | 370 | n = slirp_send(so, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ |
f0cbd3ec | 371 | #ifdef DEBUG |
c7950fb3 | 372 | if (n != len) { |
226ea7a9 | 373 | DEBUG_ERROR("Didn't send all data urgently XXXXX"); |
c7950fb3 | 374 | } |
3b46e624 | 375 | #endif |
c7950fb3 ST |
376 | } |
377 | ||
0b466065 PM |
378 | if (n < 0) { |
379 | return n; | |
f0cbd3ec | 380 | } |
0b466065 | 381 | so->so_urgc -= n; |
226ea7a9 | 382 | DEBUG_MISC(" ---2 sent %d bytes urgent data, %d urgent bytes left", n, so->so_urgc); |
5fafdf24 | 383 | |
f0cbd3ec FB |
384 | sb->sb_cc -= n; |
385 | sb->sb_rptr += n; | |
386 | if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) | |
387 | sb->sb_rptr -= sb->sb_datalen; | |
5fafdf24 | 388 | |
f0cbd3ec FB |
389 | return n; |
390 | } | |
391 | ||
392 | /* | |
5fafdf24 | 393 | * Write data from so_rcv to so's socket, |
f0cbd3ec FB |
394 | * updating all sbuf field as necessary |
395 | */ | |
396 | int | |
511d2b14 | 397 | sowrite(struct socket *so) |
f0cbd3ec FB |
398 | { |
399 | int n,nn; | |
400 | struct sbuf *sb = &so->so_rcv; | |
401 | int len = sb->sb_cc; | |
402 | struct iovec iov[2]; | |
5fafdf24 | 403 | |
f0cbd3ec | 404 | DEBUG_CALL("sowrite"); |
ecc804ca | 405 | DEBUG_ARG("so = %p", so); |
5fafdf24 | 406 | |
f0cbd3ec | 407 | if (so->so_urgc) { |
75cb298d PM |
408 | uint32_t expected = so->so_urgc; |
409 | if (sosendoob(so) < expected) { | |
410 | /* Treat a short write as a fatal error too, | |
411 | * rather than continuing on and sending the urgent | |
412 | * data as if it were non-urgent and leaving the | |
413 | * so_urgc count wrong. | |
414 | */ | |
415 | goto err_disconnected; | |
416 | } | |
f0cbd3ec FB |
417 | if (sb->sb_cc == 0) |
418 | return 0; | |
419 | } | |
420 | ||
421 | /* | |
422 | * No need to check if there's something to write, | |
423 | * sowrite wouldn't have been called otherwise | |
424 | */ | |
5fafdf24 | 425 | |
f0cbd3ec | 426 | iov[0].iov_base = sb->sb_rptr; |
66029f6a BS |
427 | iov[1].iov_base = NULL; |
428 | iov[1].iov_len = 0; | |
f0cbd3ec FB |
429 | if (sb->sb_rptr < sb->sb_wptr) { |
430 | iov[0].iov_len = sb->sb_wptr - sb->sb_rptr; | |
431 | /* Should never succeed, but... */ | |
432 | if (iov[0].iov_len > len) iov[0].iov_len = len; | |
433 | n = 1; | |
434 | } else { | |
435 | iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; | |
436 | if (iov[0].iov_len > len) iov[0].iov_len = len; | |
437 | len -= iov[0].iov_len; | |
438 | if (len) { | |
439 | iov[1].iov_base = sb->sb_data; | |
440 | iov[1].iov_len = sb->sb_wptr - sb->sb_data; | |
441 | if (iov[1].iov_len > len) iov[1].iov_len = len; | |
442 | n = 2; | |
443 | } else | |
444 | n = 1; | |
445 | } | |
446 | /* Check if there's urgent data to send, and if so, send it */ | |
447 | ||
e1c5a2b3 | 448 | nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0); |
f0cbd3ec FB |
449 | /* This should never happen, but people tell me it does *shrug* */ |
450 | if (nn < 0 && (errno == EAGAIN || errno == EINTR)) | |
451 | return 0; | |
5fafdf24 | 452 | |
f0cbd3ec | 453 | if (nn <= 0) { |
75cb298d | 454 | goto err_disconnected; |
f0cbd3ec | 455 | } |
5fafdf24 | 456 | |
3bc2175d FB |
457 | if (n == 2 && nn == iov[0].iov_len) { |
458 | int ret; | |
e1c5a2b3 | 459 | ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0); |
3bc2175d FB |
460 | if (ret > 0) |
461 | nn += ret; | |
462 | } | |
226ea7a9 | 463 | DEBUG_MISC(" ... wrote nn = %d bytes", nn); |
5fafdf24 | 464 | |
f0cbd3ec FB |
465 | /* Update sbuf */ |
466 | sb->sb_cc -= nn; | |
467 | sb->sb_rptr += nn; | |
468 | if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) | |
469 | sb->sb_rptr -= sb->sb_datalen; | |
5fafdf24 | 470 | |
f0cbd3ec FB |
471 | /* |
472 | * If in DRAIN mode, and there's no more data, set | |
473 | * it CANTSENDMORE | |
474 | */ | |
475 | if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0) | |
476 | sofcantsendmore(so); | |
5fafdf24 | 477 | |
f0cbd3ec | 478 | return nn; |
75cb298d PM |
479 | |
480 | err_disconnected: | |
226ea7a9 | 481 | DEBUG_MISC(" --- sowrite disconnected, so->so_state = %x, errno = %d", |
2afbb788 | 482 | so->so_state, errno); |
75cb298d PM |
483 | sofcantsendmore(so); |
484 | tcp_sockclosed(sototcpcb(so)); | |
485 | return -1; | |
f0cbd3ec FB |
486 | } |
487 | ||
488 | /* | |
489 | * recvfrom() a UDP socket | |
490 | */ | |
491 | void | |
511d2b14 | 492 | sorecvfrom(struct socket *so) |
f0cbd3ec | 493 | { |
eae303ff | 494 | struct sockaddr_storage addr; |
5379229a | 495 | struct sockaddr_storage saddr, daddr; |
eae303ff | 496 | socklen_t addrlen = sizeof(struct sockaddr_storage); |
5fafdf24 | 497 | |
f0cbd3ec | 498 | DEBUG_CALL("sorecvfrom"); |
ecc804ca | 499 | DEBUG_ARG("so = %p", so); |
5fafdf24 | 500 | |
f0cbd3ec FB |
501 | if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */ |
502 | char buff[256]; | |
503 | int len; | |
3b46e624 | 504 | |
5fafdf24 | 505 | len = recvfrom(so->s, buff, 256, 0, |
f0cbd3ec FB |
506 | (struct sockaddr *)&addr, &addrlen); |
507 | /* XXX Check if reply is "correct"? */ | |
3b46e624 | 508 | |
f0cbd3ec | 509 | if(len == -1 || len == 0) { |
d7df0b41 | 510 | uint8_t code=ICMP_UNREACH_PORT; |
f0cbd3ec FB |
511 | |
512 | if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; | |
513 | else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; | |
3b46e624 | 514 | |
226ea7a9 | 515 | DEBUG_MISC(" udp icmp rx errno = %d-%s", |
2afbb788 | 516 | errno,strerror(errno)); |
de40abfe | 517 | icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno)); |
f0cbd3ec FB |
518 | } else { |
519 | icmp_reflect(so->so_m); | |
511d2b14 | 520 | so->so_m = NULL; /* Don't m_free() it again! */ |
f0cbd3ec FB |
521 | } |
522 | /* No need for this socket anymore, udp_detach it */ | |
523 | udp_detach(so); | |
524 | } else { /* A "normal" UDP packet */ | |
525 | struct mbuf *m; | |
c5b76b38 BS |
526 | int len; |
527 | #ifdef _WIN32 | |
528 | unsigned long n; | |
529 | #else | |
530 | int n; | |
531 | #endif | |
f0cbd3ec | 532 | |
6c419a1e VL |
533 | if (ioctlsocket(so->s, FIONREAD, &n) != 0) { |
534 | DEBUG_MISC(" ioctlsocket errno = %d-%s\n", | |
535 | errno,strerror(errno)); | |
536 | return; | |
537 | } | |
538 | if (n == 0) { | |
539 | return; | |
540 | } | |
541 | ||
460fec67 JK |
542 | m = m_get(so->slirp); |
543 | if (!m) { | |
544 | return; | |
545 | } | |
98c63057 GS |
546 | switch (so->so_ffamily) { |
547 | case AF_INET: | |
548 | m->m_data += IF_MAXLINKHDR + sizeof(struct udpiphdr); | |
549 | break; | |
550 | case AF_INET6: | |
551 | m->m_data += IF_MAXLINKHDR + sizeof(struct ip6) | |
552 | + sizeof(struct udphdr); | |
553 | break; | |
554 | default: | |
555 | g_assert_not_reached(); | |
556 | break; | |
557 | } | |
3b46e624 | 558 | |
5fafdf24 | 559 | /* |
f0cbd3ec FB |
560 | * XXX Shouldn't FIONREAD packets destined for port 53, |
561 | * but I don't know the max packet size for DNS lookups | |
562 | */ | |
563 | len = M_FREEROOM(m); | |
564 | /* if (so->so_fport != htons(53)) { */ | |
3b46e624 | 565 | |
f0cbd3ec FB |
566 | if (n > len) { |
567 | n = (m->m_data - m->m_dat) + m->m_len + n + 1; | |
568 | m_inc(m, n); | |
569 | len = M_FREEROOM(m); | |
570 | } | |
571 | /* } */ | |
3b46e624 | 572 | |
f0cbd3ec FB |
573 | m->m_len = recvfrom(so->s, m->m_data, len, 0, |
574 | (struct sockaddr *)&addr, &addrlen); | |
226ea7a9 | 575 | DEBUG_MISC(" did recvfrom %d, errno = %d-%s", |
2afbb788 | 576 | m->m_len, errno,strerror(errno)); |
f0cbd3ec | 577 | if(m->m_len<0) { |
15d62af4 GS |
578 | /* Report error as ICMP */ |
579 | switch (so->so_lfamily) { | |
580 | uint8_t code; | |
581 | case AF_INET: | |
582 | code = ICMP_UNREACH_PORT; | |
583 | ||
584 | if (errno == EHOSTUNREACH) { | |
585 | code = ICMP_UNREACH_HOST; | |
586 | } else if (errno == ENETUNREACH) { | |
587 | code = ICMP_UNREACH_NET; | |
588 | } | |
589 | ||
226ea7a9 | 590 | DEBUG_MISC(" rx error, tx icmp ICMP_UNREACH:%i", code); |
15d62af4 GS |
591 | icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno)); |
592 | break; | |
593 | case AF_INET6: | |
594 | code = ICMP6_UNREACH_PORT; | |
595 | ||
596 | if (errno == EHOSTUNREACH) { | |
597 | code = ICMP6_UNREACH_ADDRESS; | |
598 | } else if (errno == ENETUNREACH) { | |
599 | code = ICMP6_UNREACH_NO_ROUTE; | |
600 | } | |
601 | ||
226ea7a9 | 602 | DEBUG_MISC(" rx error, tx icmp6 ICMP_UNREACH:%i", code); |
15d62af4 GS |
603 | icmp6_send_error(so->so_m, ICMP6_UNREACH, code); |
604 | break; | |
605 | default: | |
606 | g_assert_not_reached(); | |
607 | break; | |
608 | } | |
f0cbd3ec FB |
609 | m_free(m); |
610 | } else { | |
611 | /* | |
612 | * Hack: domain name lookup will be used the most for UDP, | |
613 | * and since they'll only be used once there's no need | |
614 | * for the 4 minute (or whatever) timeout... So we time them | |
615 | * out much quicker (10 seconds for now...) | |
616 | */ | |
617 | if (so->so_expire) { | |
618 | if (so->so_fport == htons(53)) | |
619 | so->so_expire = curtime + SO_EXPIREFAST; | |
620 | else | |
621 | so->so_expire = curtime + SO_EXPIRE; | |
622 | } | |
623 | ||
5fafdf24 | 624 | /* |
f0cbd3ec | 625 | * If this packet was destined for CTL_ADDR, |
5379229a | 626 | * make it look like that's where it came from |
f0cbd3ec | 627 | */ |
5379229a GS |
628 | saddr = addr; |
629 | sotranslate_in(so, &saddr); | |
630 | daddr = so->lhost.ss; | |
631 | ||
eae303ff GS |
632 | switch (so->so_ffamily) { |
633 | case AF_INET: | |
5379229a GS |
634 | udp_output(so, m, (struct sockaddr_in *) &saddr, |
635 | (struct sockaddr_in *) &daddr, | |
636 | so->so_iptos); | |
eae303ff | 637 | break; |
15d62af4 GS |
638 | case AF_INET6: |
639 | udp6_output(so, m, (struct sockaddr_in6 *) &saddr, | |
640 | (struct sockaddr_in6 *) &daddr); | |
641 | break; | |
eae303ff | 642 | default: |
15d62af4 | 643 | g_assert_not_reached(); |
eae303ff GS |
644 | break; |
645 | } | |
f0cbd3ec FB |
646 | } /* rx error */ |
647 | } /* if ping packet */ | |
648 | } | |
649 | ||
650 | /* | |
651 | * sendto() a socket | |
652 | */ | |
653 | int | |
511d2b14 | 654 | sosendto(struct socket *so, struct mbuf *m) |
f0cbd3ec FB |
655 | { |
656 | int ret; | |
5379229a | 657 | struct sockaddr_storage addr; |
f0cbd3ec FB |
658 | |
659 | DEBUG_CALL("sosendto"); | |
ecc804ca SW |
660 | DEBUG_ARG("so = %p", so); |
661 | DEBUG_ARG("m = %p", m); | |
5fafdf24 | 662 | |
5379229a GS |
663 | addr = so->fhost.ss; |
664 | DEBUG_CALL(" sendto()ing)"); | |
665 | sotranslate_out(so, &addr); | |
5fafdf24 | 666 | |
f0cbd3ec FB |
667 | /* Don't care what port we get */ |
668 | ret = sendto(so->s, m->m_data, m->m_len, 0, | |
0d48dfed | 669 | (struct sockaddr *)&addr, sockaddr_size(&addr)); |
f0cbd3ec FB |
670 | if (ret < 0) |
671 | return -1; | |
5fafdf24 | 672 | |
f0cbd3ec FB |
673 | /* |
674 | * Kill the socket if there's no reply in 4 minutes, | |
675 | * but only if it's an expirable socket | |
676 | */ | |
677 | if (so->so_expire) | |
678 | so->so_expire = curtime + SO_EXPIRE; | |
f932b6ce JK |
679 | so->so_state &= SS_PERSISTENT_MASK; |
680 | so->so_state |= SS_ISFCONNECTED; /* So that it gets select()ed */ | |
f0cbd3ec FB |
681 | return 0; |
682 | } | |
683 | ||
684 | /* | |
3c6a0580 | 685 | * Listen for incoming TCP connections |
f0cbd3ec FB |
686 | */ |
687 | struct socket * | |
d7df0b41 MAL |
688 | tcp_listen(Slirp *slirp, uint32_t haddr, unsigned hport, uint32_t laddr, |
689 | unsigned lport, int flags) | |
f0cbd3ec | 690 | { |
ffe02f55 | 691 | /* TODO: IPv6 */ |
f0cbd3ec FB |
692 | struct sockaddr_in addr; |
693 | struct socket *so; | |
242acf3a AZ |
694 | int s, opt = 1; |
695 | socklen_t addrlen = sizeof(addr); | |
ab07b980 | 696 | memset(&addr, 0, addrlen); |
f0cbd3ec | 697 | |
3c6a0580 | 698 | DEBUG_CALL("tcp_listen"); |
8ee2022b | 699 | DEBUG_ARG("haddr = %s", inet_ntoa((struct in_addr){.s_addr = haddr})); |
3ad9319f | 700 | DEBUG_ARG("hport = %d", ntohs(hport)); |
8ee2022b | 701 | DEBUG_ARG("laddr = %s", inet_ntoa((struct in_addr){.s_addr = laddr})); |
3ad9319f | 702 | DEBUG_ARG("lport = %d", ntohs(lport)); |
f0cbd3ec | 703 | DEBUG_ARG("flags = %x", flags); |
5fafdf24 | 704 | |
460fec67 | 705 | so = socreate(slirp); |
5fafdf24 | 706 | |
f0cbd3ec FB |
707 | /* Don't tcp_attach... we don't need so_snd nor so_rcv */ |
708 | if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) { | |
84ec9bfa PM |
709 | g_free(so); |
710 | return NULL; | |
f0cbd3ec | 711 | } |
460fec67 | 712 | insque(so, &slirp->tcb); |
5fafdf24 TS |
713 | |
714 | /* | |
f0cbd3ec FB |
715 | * SS_FACCEPTONCE sockets must time out. |
716 | */ | |
717 | if (flags & SS_FACCEPTONCE) | |
718 | so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2; | |
5fafdf24 | 719 | |
f932b6ce JK |
720 | so->so_state &= SS_PERSISTENT_MASK; |
721 | so->so_state |= (SS_FACCEPTCONN | flags); | |
eae303ff | 722 | so->so_lfamily = AF_INET; |
f0cbd3ec FB |
723 | so->so_lport = lport; /* Kept in network format */ |
724 | so->so_laddr.s_addr = laddr; /* Ditto */ | |
5fafdf24 | 725 | |
f0cbd3ec | 726 | addr.sin_family = AF_INET; |
3c6a0580 JK |
727 | addr.sin_addr.s_addr = haddr; |
728 | addr.sin_port = hport; | |
5fafdf24 | 729 | |
707bd47e MAL |
730 | if (((s = slirp_socket(AF_INET,SOCK_STREAM,0)) < 0) || |
731 | (slirp_socket_set_fast_reuse(s) < 0) || | |
f0cbd3ec FB |
732 | (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || |
733 | (listen(s,1) < 0)) { | |
734 | int tmperrno = errno; /* Don't clobber the real reason we failed */ | |
3b46e624 | 735 | |
bd5d2353 | 736 | if (s >= 0) { |
fdbfba8c | 737 | closesocket(s); |
bd5d2353 | 738 | } |
f0cbd3ec FB |
739 | sofree(so); |
740 | /* Restore the real errno */ | |
02d2c54c FB |
741 | #ifdef _WIN32 |
742 | WSASetLastError(tmperrno); | |
743 | #else | |
f0cbd3ec | 744 | errno = tmperrno; |
02d2c54c | 745 | #endif |
f0cbd3ec FB |
746 | return NULL; |
747 | } | |
fdbfba8c | 748 | setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int)); |
05658ecb | 749 | opt = 1; |
fdbfba8c | 750 | setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int)); |
5fafdf24 | 751 | |
f0cbd3ec | 752 | getsockname(s,(struct sockaddr *)&addr,&addrlen); |
eae303ff | 753 | so->so_ffamily = AF_INET; |
f0cbd3ec FB |
754 | so->so_fport = addr.sin_port; |
755 | if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) | |
460fec67 | 756 | so->so_faddr = slirp->vhost_addr; |
f0cbd3ec FB |
757 | else |
758 | so->so_faddr = addr.sin_addr; | |
759 | ||
760 | so->s = s; | |
761 | return so; | |
762 | } | |
763 | ||
f0cbd3ec FB |
764 | /* |
765 | * Various session state calls | |
766 | * XXX Should be #define's | |
767 | * The socket state stuff needs work, these often get call 2 or 3 | |
768 | * times each when only 1 was needed | |
769 | */ | |
770 | void | |
511d2b14 | 771 | soisfconnecting(struct socket *so) |
f0cbd3ec FB |
772 | { |
773 | so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE| | |
774 | SS_FCANTSENDMORE|SS_FWDRAIN); | |
775 | so->so_state |= SS_ISFCONNECTING; /* Clobber other states */ | |
776 | } | |
777 | ||
778 | void | |
511d2b14 | 779 | soisfconnected(struct socket *so) |
f0cbd3ec FB |
780 | { |
781 | so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF); | |
782 | so->so_state |= SS_ISFCONNECTED; /* Clobber other states */ | |
783 | } | |
784 | ||
9634d903 BS |
785 | static void |
786 | sofcantrcvmore(struct socket *so) | |
f0cbd3ec FB |
787 | { |
788 | if ((so->so_state & SS_NOFDREF) == 0) { | |
789 | shutdown(so->s,0); | |
f0cbd3ec FB |
790 | } |
791 | so->so_state &= ~(SS_ISFCONNECTING); | |
f932b6ce JK |
792 | if (so->so_state & SS_FCANTSENDMORE) { |
793 | so->so_state &= SS_PERSISTENT_MASK; | |
794 | so->so_state |= SS_NOFDREF; /* Don't select it */ | |
795 | } else { | |
f0cbd3ec | 796 | so->so_state |= SS_FCANTRCVMORE; |
f932b6ce | 797 | } |
f0cbd3ec FB |
798 | } |
799 | ||
9634d903 BS |
800 | static void |
801 | sofcantsendmore(struct socket *so) | |
f0cbd3ec FB |
802 | { |
803 | if ((so->so_state & SS_NOFDREF) == 0) { | |
02d2c54c | 804 | shutdown(so->s,1); /* send FIN to fhost */ |
f0cbd3ec FB |
805 | } |
806 | so->so_state &= ~(SS_ISFCONNECTING); | |
f932b6ce JK |
807 | if (so->so_state & SS_FCANTRCVMORE) { |
808 | so->so_state &= SS_PERSISTENT_MASK; | |
809 | so->so_state |= SS_NOFDREF; /* as above */ | |
810 | } else { | |
f0cbd3ec | 811 | so->so_state |= SS_FCANTSENDMORE; |
f932b6ce | 812 | } |
f0cbd3ec FB |
813 | } |
814 | ||
f0cbd3ec FB |
815 | /* |
816 | * Set write drain mode | |
817 | * Set CANTSENDMORE once all data has been write()n | |
818 | */ | |
819 | void | |
511d2b14 | 820 | sofwdrain(struct socket *so) |
f0cbd3ec FB |
821 | { |
822 | if (so->so_rcv.sb_cc) | |
823 | so->so_state |= SS_FWDRAIN; | |
824 | else | |
825 | sofcantsendmore(so); | |
826 | } | |
5379229a GS |
827 | |
828 | /* | |
829 | * Translate addr in host addr when it is a virtual address | |
830 | */ | |
831 | void sotranslate_out(struct socket *so, struct sockaddr_storage *addr) | |
832 | { | |
833 | Slirp *slirp = so->slirp; | |
834 | struct sockaddr_in *sin = (struct sockaddr_in *)addr; | |
05061d85 | 835 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; |
5379229a GS |
836 | |
837 | switch (addr->ss_family) { | |
838 | case AF_INET: | |
839 | if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == | |
840 | slirp->vnetwork_addr.s_addr) { | |
841 | /* It's an alias */ | |
842 | if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { | |
843 | if (get_dns_addr(&sin->sin_addr) < 0) { | |
844 | sin->sin_addr = loopback_addr; | |
845 | } | |
846 | } else { | |
847 | sin->sin_addr = loopback_addr; | |
848 | } | |
849 | } | |
850 | ||
226ea7a9 | 851 | DEBUG_MISC(" addr.sin_port=%d, addr.sin_addr.s_addr=%.16s", |
2afbb788 | 852 | ntohs(sin->sin_port), inet_ntoa(sin->sin_addr)); |
5379229a GS |
853 | break; |
854 | ||
05061d85 GS |
855 | case AF_INET6: |
856 | if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6, | |
857 | slirp->vprefix_len)) { | |
858 | if (in6_equal(&so->so_faddr6, &slirp->vnameserver_addr6)) { | |
ef763fa4 ST |
859 | uint32_t scope_id; |
860 | if (get_dns6_addr(&sin6->sin6_addr, &scope_id) >= 0) { | |
861 | sin6->sin6_scope_id = scope_id; | |
862 | } else { | |
05061d85 | 863 | sin6->sin6_addr = in6addr_loopback; |
1d17654e | 864 | } |
05061d85 GS |
865 | } else { |
866 | sin6->sin6_addr = in6addr_loopback; | |
867 | } | |
868 | } | |
869 | break; | |
870 | ||
5379229a GS |
871 | default: |
872 | break; | |
873 | } | |
874 | } | |
875 | ||
876 | void sotranslate_in(struct socket *so, struct sockaddr_storage *addr) | |
877 | { | |
878 | Slirp *slirp = so->slirp; | |
879 | struct sockaddr_in *sin = (struct sockaddr_in *)addr; | |
05061d85 | 880 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; |
5379229a GS |
881 | |
882 | switch (addr->ss_family) { | |
883 | case AF_INET: | |
884 | if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) == | |
885 | slirp->vnetwork_addr.s_addr) { | |
886 | uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr; | |
887 | ||
888 | if ((so->so_faddr.s_addr & inv_mask) == inv_mask) { | |
889 | sin->sin_addr = slirp->vhost_addr; | |
890 | } else if (sin->sin_addr.s_addr == loopback_addr.s_addr || | |
891 | so->so_faddr.s_addr != slirp->vhost_addr.s_addr) { | |
892 | sin->sin_addr = so->so_faddr; | |
893 | } | |
894 | } | |
895 | break; | |
896 | ||
05061d85 GS |
897 | case AF_INET6: |
898 | if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6, | |
899 | slirp->vprefix_len)) { | |
900 | if (in6_equal(&sin6->sin6_addr, &in6addr_loopback) | |
901 | || !in6_equal(&so->so_faddr6, &slirp->vhost_addr6)) { | |
902 | sin6->sin6_addr = so->so_faddr6; | |
903 | } | |
904 | } | |
905 | break; | |
906 | ||
5379229a GS |
907 | default: |
908 | break; | |
909 | } | |
910 | } | |
911 | ||
912 | /* | |
913 | * Translate connections from localhost to the real hostname | |
914 | */ | |
915 | void sotranslate_accept(struct socket *so) | |
916 | { | |
917 | Slirp *slirp = so->slirp; | |
918 | ||
919 | switch (so->so_ffamily) { | |
920 | case AF_INET: | |
921 | if (so->so_faddr.s_addr == INADDR_ANY || | |
922 | (so->so_faddr.s_addr & loopback_mask) == | |
923 | (loopback_addr.s_addr & loopback_mask)) { | |
924 | so->so_faddr = slirp->vhost_addr; | |
925 | } | |
926 | break; | |
927 | ||
05061d85 GS |
928 | case AF_INET6: |
929 | if (in6_equal(&so->so_faddr6, &in6addr_any) || | |
930 | in6_equal(&so->so_faddr6, &in6addr_loopback)) { | |
931 | so->so_faddr6 = slirp->vhost_addr6; | |
932 | } | |
933 | break; | |
934 | ||
5379229a GS |
935 | default: |
936 | break; | |
937 | } | |
938 | } | |
c21d9594 MAL |
939 | |
940 | void sodrop(struct socket *s, int num) | |
941 | { | |
942 | if (sbdrop(&s->so_snd, num)) { | |
3e0fad3a | 943 | s->slirp->cb->notify(s->slirp->opaque); |
c21d9594 MAL |
944 | } |
945 | } |