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