|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1988, 1990, 1993
3: * The Regents of the University of California. All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
1.1.1.5 root 13: * 3. Neither the name of the University nor the names of its contributors
1.1 root 14: * may be used to endorse or promote products derived from this software
15: * without specific prior written permission.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
28: *
29: * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93
30: * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp
31: */
32:
33: /*
34: * Changes and additions relating to SLiRP
35: * Copyright (c) 1995 Danny Gasparovski.
1.1.1.4 root 36: *
37: * Please read the file COPYRIGHT for the
1.1 root 38: * terms and conditions of the copyright.
39: */
40:
41: #include <slirp.h>
42:
43: /* patchable/settable parameters for tcp */
1.1.1.4 root 44: /* Don't do rfc1323 performance enhancements */
45: #define TCP_DO_RFC1323 0
1.1 root 46:
47: /*
48: * Tcp initialization
49: */
50: void
1.1.1.6 root 51: tcp_init(Slirp *slirp)
1.1 root 52: {
1.1.1.6 root 53: slirp->tcp_iss = 1; /* wrong */
54: slirp->tcb.so_next = slirp->tcb.so_prev = &slirp->tcb;
55: slirp->tcp_last_so = &slirp->tcb;
1.1 root 56: }
57:
1.1.1.11! root 58: void tcp_cleanup(Slirp *slirp)
! 59: {
! 60: while (slirp->tcb.so_next != &slirp->tcb) {
! 61: tcp_close(sototcpcb(slirp->tcb.so_next));
! 62: }
! 63: }
! 64:
1.1 root 65: /*
66: * Create template to be used to send tcp packets on a connection.
67: * Call after host entry created, fills
68: * in a skeletal tcp/ip header, minimizing the amount of work
69: * necessary when the connection is used.
70: */
71: void
1.1.1.6 root 72: tcp_template(struct tcpcb *tp)
1.1 root 73: {
74: struct socket *so = tp->t_socket;
75: register struct tcpiphdr *n = &tp->t_template;
76:
1.1.1.5 root 77: n->ti_mbuf = NULL;
1.1 root 78: n->ti_x1 = 0;
79: n->ti_pr = IPPROTO_TCP;
80: n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
81: n->ti_src = so->so_faddr;
82: n->ti_dst = so->so_laddr;
83: n->ti_sport = so->so_fport;
84: n->ti_dport = so->so_lport;
1.1.1.4 root 85:
1.1 root 86: n->ti_seq = 0;
87: n->ti_ack = 0;
88: n->ti_x2 = 0;
89: n->ti_off = 5;
90: n->ti_flags = 0;
91: n->ti_win = 0;
92: n->ti_sum = 0;
93: n->ti_urp = 0;
94: }
95:
96: /*
97: * Send a single message to the TCP at address specified by
98: * the given TCP/IP header. If m == 0, then we make a copy
99: * of the tcpiphdr at ti and send directly to the addressed host.
100: * This is used to force keep alive messages out using the TCP
101: * template for a connection tp->t_template. If flags are given
102: * then we send a message back to the TCP which originated the
103: * segment ti, and discard the mbuf containing it and any other
104: * attached mbufs.
105: *
106: * In any case the ack and sequence number of the transmitted
107: * segment are as specified by the parameters.
108: */
109: void
1.1.1.6 root 110: tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
111: tcp_seq ack, tcp_seq seq, int flags)
1.1 root 112: {
113: register int tlen;
114: int win = 0;
115:
116: DEBUG_CALL("tcp_respond");
117: DEBUG_ARG("tp = %lx", (long)tp);
118: DEBUG_ARG("ti = %lx", (long)ti);
119: DEBUG_ARG("m = %lx", (long)m);
120: DEBUG_ARG("ack = %u", ack);
121: DEBUG_ARG("seq = %u", seq);
122: DEBUG_ARG("flags = %x", flags);
1.1.1.4 root 123:
1.1 root 124: if (tp)
125: win = sbspace(&tp->t_socket->so_rcv);
1.1.1.6 root 126: if (m == NULL) {
127: if ((m = m_get(tp->t_socket->slirp)) == NULL)
1.1 root 128: return;
129: tlen = 0;
1.1.1.4 root 130: m->m_data += IF_MAXLINKHDR;
1.1 root 131: *mtod(m, struct tcpiphdr *) = *ti;
132: ti = mtod(m, struct tcpiphdr *);
133: flags = TH_ACK;
134: } else {
1.1.1.4 root 135: /*
1.1 root 136: * ti points into m so the next line is just making
137: * the mbuf point to ti
138: */
139: m->m_data = (caddr_t)ti;
1.1.1.4 root 140:
1.1 root 141: m->m_len = sizeof (struct tcpiphdr);
142: tlen = 0;
143: #define xchg(a,b,type) { type t; t=a; a=b; b=t; }
1.1.1.8 root 144: xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t);
145: xchg(ti->ti_dport, ti->ti_sport, uint16_t);
1.1 root 146: #undef xchg
147: }
148: ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
149: tlen += sizeof (struct tcpiphdr);
150: m->m_len = tlen;
151:
1.1.1.6 root 152: ti->ti_mbuf = NULL;
1.1 root 153: ti->ti_x1 = 0;
154: ti->ti_seq = htonl(seq);
155: ti->ti_ack = htonl(ack);
156: ti->ti_x2 = 0;
157: ti->ti_off = sizeof (struct tcphdr) >> 2;
158: ti->ti_flags = flags;
159: if (tp)
1.1.1.8 root 160: ti->ti_win = htons((uint16_t) (win >> tp->rcv_scale));
1.1 root 161: else
1.1.1.8 root 162: ti->ti_win = htons((uint16_t)win);
1.1 root 163: ti->ti_urp = 0;
164: ti->ti_sum = 0;
165: ti->ti_sum = cksum(m, tlen);
166: ((struct ip *)ti)->ip_len = tlen;
167:
1.1.1.4 root 168: if(flags & TH_RST)
1.1 root 169: ((struct ip *)ti)->ip_ttl = MAXTTL;
1.1.1.4 root 170: else
171: ((struct ip *)ti)->ip_ttl = IPDEFTTL;
172:
1.1 root 173: (void) ip_output((struct socket *)0, m);
174: }
175:
176: /*
177: * Create a new TCP control block, making an
178: * empty reassembly queue and hooking it to the argument
179: * protocol control block.
180: */
181: struct tcpcb *
1.1.1.6 root 182: tcp_newtcpcb(struct socket *so)
1.1 root 183: {
184: register struct tcpcb *tp;
1.1.1.4 root 185:
1.1 root 186: tp = (struct tcpcb *)malloc(sizeof(*tp));
187: if (tp == NULL)
188: return ((struct tcpcb *)0);
1.1.1.4 root 189:
1.1 root 190: memset((char *) tp, 0, sizeof(struct tcpcb));
1.1.1.5 root 191: tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp;
1.1.1.4 root 192: tp->t_maxseg = TCP_MSS;
193:
194: tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
1.1 root 195: tp->t_socket = so;
1.1.1.4 root 196:
1.1 root 197: /*
198: * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
199: * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives
200: * reasonable initial retransmit time.
201: */
202: tp->t_srtt = TCPTV_SRTTBASE;
1.1.1.4 root 203: tp->t_rttvar = TCPTV_SRTTDFLT << 2;
1.1 root 204: tp->t_rttmin = TCPTV_MIN;
205:
1.1.1.4 root 206: TCPT_RANGESET(tp->t_rxtcur,
1.1 root 207: ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
208: TCPTV_MIN, TCPTV_REXMTMAX);
209:
210: tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
211: tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
212: tp->t_state = TCPS_CLOSED;
1.1.1.4 root 213:
1.1 root 214: so->so_tcpcb = tp;
215:
216: return (tp);
217: }
218:
219: /*
220: * Drop a TCP connection, reporting
221: * the specified error. If connection is synchronized,
222: * then send a RST to peer.
223: */
1.1.1.4 root 224: struct tcpcb *tcp_drop(struct tcpcb *tp, int err)
1.1 root 225: {
226: DEBUG_CALL("tcp_drop");
227: DEBUG_ARG("tp = %lx", (long)tp);
228: DEBUG_ARG("errno = %d", errno);
1.1.1.4 root 229:
1.1 root 230: if (TCPS_HAVERCVDSYN(tp->t_state)) {
231: tp->t_state = TCPS_CLOSED;
232: (void) tcp_output(tp);
1.1.1.6 root 233: }
1.1 root 234: return (tcp_close(tp));
235: }
236:
237: /*
238: * Close a TCP control block:
239: * discard all space held by the tcp
240: * discard internet protocol block
241: * wake up any sleepers
242: */
243: struct tcpcb *
1.1.1.6 root 244: tcp_close(struct tcpcb *tp)
1.1 root 245: {
246: register struct tcpiphdr *t;
247: struct socket *so = tp->t_socket;
1.1.1.6 root 248: Slirp *slirp = so->slirp;
1.1 root 249: register struct mbuf *m;
250:
251: DEBUG_CALL("tcp_close");
252: DEBUG_ARG("tp = %lx", (long )tp);
1.1.1.4 root 253:
1.1 root 254: /* free the reassembly queue, if any */
1.1.1.5 root 255: t = tcpfrag_list_first(tp);
256: while (!tcpfrag_list_end(t, tp)) {
257: t = tcpiphdr_next(t);
258: m = tcpiphdr_prev(t)->ti_mbuf;
259: remque(tcpiphdr2qlink(tcpiphdr_prev(t)));
1.1.1.9 root 260: m_free(m);
1.1 root 261: }
262: free(tp);
1.1.1.6 root 263: so->so_tcpcb = NULL;
1.1 root 264: /* clobber input socket cache if we're closing the cached connection */
1.1.1.6 root 265: if (so == slirp->tcp_last_so)
266: slirp->tcp_last_so = &slirp->tcb;
1.1 root 267: closesocket(so->s);
268: sbfree(&so->so_rcv);
269: sbfree(&so->so_snd);
270: sofree(so);
271: return ((struct tcpcb *)0);
272: }
273:
274: /*
275: * TCP protocol interface to socket abstraction.
276: */
277:
278: /*
279: * User issued close, and wish to trail through shutdown states:
280: * if never received SYN, just forget it. If got a SYN from peer,
281: * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
282: * If already got a FIN from peer, then almost done; go to LAST_ACK
283: * state. In all other cases, have already sent FIN to peer (e.g.
284: * after PRU_SHUTDOWN), and just have to play tedious game waiting
285: * for peer to send FIN or not respond to keep-alives, etc.
286: * We can let the user exit from the close as soon as the FIN is acked.
287: */
288: void
1.1.1.6 root 289: tcp_sockclosed(struct tcpcb *tp)
1.1 root 290: {
291:
292: DEBUG_CALL("tcp_sockclosed");
293: DEBUG_ARG("tp = %lx", (long)tp);
1.1.1.4 root 294:
1.1 root 295: switch (tp->t_state) {
296:
297: case TCPS_CLOSED:
298: case TCPS_LISTEN:
299: case TCPS_SYN_SENT:
300: tp->t_state = TCPS_CLOSED;
301: tp = tcp_close(tp);
302: break;
303:
304: case TCPS_SYN_RECEIVED:
305: case TCPS_ESTABLISHED:
306: tp->t_state = TCPS_FIN_WAIT_1;
307: break;
308:
309: case TCPS_CLOSE_WAIT:
310: tp->t_state = TCPS_LAST_ACK;
311: break;
312: }
313: if (tp)
314: tcp_output(tp);
315: }
316:
1.1.1.4 root 317: /*
1.1 root 318: * Connect to a host on the Internet
319: * Called by tcp_input
320: * Only do a connect, the tcp fields will be set in tcp_input
321: * return 0 if there's a result of the connect,
322: * else return -1 means we're still connecting
323: * The return value is almost always -1 since the socket is
1.1.1.4 root 324: * nonblocking. Connect returns after the SYN is sent, and does
1.1 root 325: * not wait for ACK+SYN.
326: */
1.1.1.6 root 327: int tcp_fconnect(struct socket *so)
1.1 root 328: {
1.1.1.6 root 329: Slirp *slirp = so->slirp;
1.1 root 330: int ret=0;
1.1.1.4 root 331:
1.1 root 332: DEBUG_CALL("tcp_fconnect");
333: DEBUG_ARG("so = %lx", (long )so);
334:
1.1.1.7 root 335: if( (ret = so->s = qemu_socket(AF_INET,SOCK_STREAM,0)) >= 0) {
1.1 root 336: int opt, s=so->s;
337: struct sockaddr_in addr;
338:
1.1.1.11! root 339: socket_set_nonblock(s);
1.1 root 340: opt = 1;
341: setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt ));
342: opt = 1;
343: setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt ));
1.1.1.4 root 344:
1.1 root 345: addr.sin_family = AF_INET;
1.1.1.6 root 346: if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
347: slirp->vnetwork_addr.s_addr) {
1.1 root 348: /* It's an alias */
1.1.1.6 root 349: if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
1.1.1.7 root 350: if (get_dns_addr(&addr.sin_addr) < 0)
351: addr.sin_addr = loopback_addr;
1.1.1.6 root 352: } else {
1.1 root 353: addr.sin_addr = loopback_addr;
354: }
355: } else
356: addr.sin_addr = so->so_faddr;
357: addr.sin_port = so->so_fport;
1.1.1.4 root 358:
1.1 root 359: DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, "
1.1.1.4 root 360: "addr.sin_addr.s_addr=%.16s\n",
1.1 root 361: ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
362: /* We don't care what port we get */
363: ret = connect(s,(struct sockaddr *)&addr,sizeof (addr));
1.1.1.4 root 364:
1.1 root 365: /*
366: * If it's not in progress, it failed, so we just return 0,
367: * without clearing SS_NOFDREF
368: */
369: soisfconnecting(so);
370: }
371:
372: return(ret);
373: }
374:
375: /*
376: * Accept the socket and connect to the local-host
1.1.1.4 root 377: *
1.1 root 378: * We have a problem. The correct thing to do would be
379: * to first connect to the local-host, and only if the
380: * connection is accepted, then do an accept() here.
1.1.1.4 root 381: * But, a) we need to know who's trying to connect
1.1 root 382: * to the socket to be able to SYN the local-host, and
383: * b) we are already connected to the foreign host by
384: * the time it gets to accept(), so... We simply accept
385: * here and SYN the local-host.
1.1.1.4 root 386: */
1.1 root 387: void
1.1.1.6 root 388: tcp_connect(struct socket *inso)
1.1 root 389: {
1.1.1.6 root 390: Slirp *slirp = inso->slirp;
1.1 root 391: struct socket *so;
392: struct sockaddr_in addr;
1.1.1.5 root 393: socklen_t addrlen = sizeof(struct sockaddr_in);
1.1 root 394: struct tcpcb *tp;
395: int s, opt;
396:
397: DEBUG_CALL("tcp_connect");
398: DEBUG_ARG("inso = %lx", (long)inso);
1.1.1.4 root 399:
1.1 root 400: /*
401: * If it's an SS_ACCEPTONCE socket, no need to socreate()
402: * another socket, just use the accept() socket.
403: */
404: if (inso->so_state & SS_FACCEPTONCE) {
405: /* FACCEPTONCE already have a tcpcb */
406: so = inso;
407: } else {
1.1.1.6 root 408: if ((so = socreate(slirp)) == NULL) {
1.1 root 409: /* If it failed, get rid of the pending connection */
410: closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen));
411: return;
412: }
413: if (tcp_attach(so) < 0) {
414: free(so); /* NOT sofree */
415: return;
416: }
417: so->so_laddr = inso->so_laddr;
418: so->so_lport = inso->so_lport;
419: }
1.1.1.4 root 420:
1.1 root 421: (void) tcp_mss(sototcpcb(so), 0);
422:
423: if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) {
424: tcp_close(sototcpcb(so)); /* This will sofree() as well */
425: return;
426: }
1.1.1.11! root 427: socket_set_nonblock(s);
1.1 root 428: opt = 1;
429: setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
430: opt = 1;
431: setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
1.1.1.3 root 432: opt = 1;
433: setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int));
1.1.1.4 root 434:
1.1 root 435: so->so_fport = addr.sin_port;
436: so->so_faddr = addr.sin_addr;
437: /* Translate connections from localhost to the real hostname */
438: if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr)
1.1.1.6 root 439: so->so_faddr = slirp->vhost_addr;
1.1.1.4 root 440:
1.1 root 441: /* Close the accept() socket, set right state */
442: if (inso->so_state & SS_FACCEPTONCE) {
443: closesocket(so->s); /* If we only accept once, close the accept() socket */
444: so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */
445: /* if it's not FACCEPTONCE, it's already NOFDREF */
446: }
447: so->s = s;
1.1.1.6 root 448: so->so_state |= SS_INCOMING;
1.1.1.4 root 449:
1.1 root 450: so->so_iptos = tcp_tos(so);
451: tp = sototcpcb(so);
452:
453: tcp_template(tp);
1.1.1.4 root 454:
1.1 root 455: tp->t_state = TCPS_SYN_SENT;
456: tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
1.1.1.6 root 457: tp->iss = slirp->tcp_iss;
458: slirp->tcp_iss += TCP_ISSINCR/2;
1.1 root 459: tcp_sendseqinit(tp);
460: tcp_output(tp);
461: }
462:
463: /*
464: * Attach a TCPCB to a socket.
465: */
466: int
1.1.1.6 root 467: tcp_attach(struct socket *so)
1.1 root 468: {
469: if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL)
470: return -1;
1.1.1.4 root 471:
1.1.1.6 root 472: insque(so, &so->slirp->tcb);
1.1 root 473:
474: return 0;
475: }
476:
477: /*
478: * Set the socket's type of service field
479: */
1.1.1.4 root 480: static const struct tos_t tcptos[] = {
1.1 root 481: {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */
482: {21, 21, IPTOS_LOWDELAY, EMU_FTP}, /* ftp control */
483: {0, 23, IPTOS_LOWDELAY, 0}, /* telnet */
484: {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */
485: {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT}, /* rlogin */
486: {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT}, /* shell */
487: {0, 544, IPTOS_LOWDELAY, EMU_KSH}, /* kshell */
488: {0, 543, IPTOS_LOWDELAY, 0}, /* klogin */
489: {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */
490: {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */
491: {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */
492: {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */
493: {0, 0, 0, 0}
494: };
495:
1.1.1.6 root 496: static struct emu_t *tcpemu = NULL;
1.1.1.4 root 497:
1.1 root 498: /*
499: * Return TOS according to the above table
500: */
1.1.1.8 root 501: uint8_t
1.1.1.6 root 502: tcp_tos(struct socket *so)
1.1 root 503: {
504: int i = 0;
505: struct emu_t *emup;
1.1.1.4 root 506:
1.1 root 507: while(tcptos[i].tos) {
508: if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) ||
509: (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) {
510: so->so_emu = tcptos[i].emu;
511: return tcptos[i].tos;
512: }
513: i++;
514: }
1.1.1.4 root 515:
1.1 root 516: /* Nope, lets see if there's a user-added one */
517: for (emup = tcpemu; emup; emup = emup->next) {
518: if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) ||
519: (emup->lport && (ntohs(so->so_lport) == emup->lport))) {
520: so->so_emu = emup->emu;
521: return emup->tos;
522: }
523: }
1.1.1.4 root 524:
1.1 root 525: return 0;
526: }
527:
528: /*
529: * Emulate programs that try and connect to us
530: * This includes ftp (the data connection is
531: * initiated by the server) and IRC (DCC CHAT and
532: * DCC SEND) for now
1.1.1.4 root 533: *
1.1 root 534: * NOTE: It's possible to crash SLiRP by sending it
535: * unstandard strings to emulate... if this is a problem,
536: * more checks are needed here
537: *
538: * XXX Assumes the whole command came in one packet
1.1.1.4 root 539: *
1.1 root 540: * XXX Some ftp clients will have their TOS set to
541: * LOWDELAY and so Nagel will kick in. Because of this,
542: * we'll get the first letter, followed by the rest, so
543: * we simply scan for ORT instead of PORT...
544: * DCC doesn't have this problem because there's other stuff
545: * in the packet before the DCC command.
1.1.1.4 root 546: *
547: * Return 1 if the mbuf m is still valid and should be
1.1 root 548: * sbappend()ed
1.1.1.4 root 549: *
1.1 root 550: * NOTE: if you return 0 you MUST m_free() the mbuf!
551: */
552: int
1.1.1.6 root 553: tcp_emu(struct socket *so, struct mbuf *m)
1.1 root 554: {
1.1.1.6 root 555: Slirp *slirp = so->slirp;
1.1 root 556: u_int n1, n2, n3, n4, n5, n6;
1.1.1.5 root 557: char buff[257];
1.1.1.8 root 558: uint32_t laddr;
1.1 root 559: u_int lport;
560: char *bptr;
1.1.1.4 root 561:
1.1 root 562: DEBUG_CALL("tcp_emu");
563: DEBUG_ARG("so = %lx", (long)so);
564: DEBUG_ARG("m = %lx", (long)m);
1.1.1.4 root 565:
1.1 root 566: switch(so->so_emu) {
567: int x, i;
1.1.1.4 root 568:
1.1 root 569: case EMU_IDENT:
570: /*
571: * Identification protocol as per rfc-1413
572: */
1.1.1.4 root 573:
1.1 root 574: {
575: struct socket *tmpso;
576: struct sockaddr_in addr;
1.1.1.5 root 577: socklen_t addrlen = sizeof(struct sockaddr_in);
1.1 root 578: struct sbuf *so_rcv = &so->so_rcv;
1.1.1.4 root 579:
1.1 root 580: memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
581: so_rcv->sb_wptr += m->m_len;
582: so_rcv->sb_rptr += m->m_len;
583: m->m_data[m->m_len] = 0; /* NULL terminate */
584: if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) {
1.1.1.4 root 585: if (sscanf(so_rcv->sb_data, "%u%*[ ,]%u", &n1, &n2) == 2) {
1.1 root 586: HTONS(n1);
587: HTONS(n2);
588: /* n2 is the one on our host */
1.1.1.6 root 589: for (tmpso = slirp->tcb.so_next;
590: tmpso != &slirp->tcb;
591: tmpso = tmpso->so_next) {
1.1 root 592: if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr &&
593: tmpso->so_lport == n2 &&
594: tmpso->so_faddr.s_addr == so->so_faddr.s_addr &&
595: tmpso->so_fport == n1) {
596: if (getsockname(tmpso->s,
597: (struct sockaddr *)&addr, &addrlen) == 0)
598: n2 = ntohs(addr.sin_port);
599: break;
600: }
601: }
602: }
1.1.1.5 root 603: so_rcv->sb_cc = snprintf(so_rcv->sb_data,
604: so_rcv->sb_datalen,
605: "%d,%d\r\n", n1, n2);
1.1 root 606: so_rcv->sb_rptr = so_rcv->sb_data;
607: so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc;
608: }
609: m_free(m);
610: return 0;
611: }
1.1.1.4 root 612:
1.1 root 613: case EMU_FTP: /* ftp */
1.1.1.6 root 614: *(m->m_data+m->m_len) = 0; /* NUL terminate for strstr */
1.1 root 615: if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
616: /*
617: * Need to emulate the PORT command
1.1.1.4 root 618: */
619: x = sscanf(bptr, "ORT %u,%u,%u,%u,%u,%u\r\n%256[^\177]",
1.1 root 620: &n1, &n2, &n3, &n4, &n5, &n6, buff);
621: if (x < 6)
622: return 1;
1.1.1.4 root 623:
1.1 root 624: laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
625: lport = htons((n5 << 8) | (n6));
1.1.1.4 root 626:
1.1.1.6 root 627: if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr,
628: lport, SS_FACCEPTONCE)) == NULL) {
1.1 root 629: return 1;
1.1.1.6 root 630: }
1.1 root 631: n6 = ntohs(so->so_fport);
1.1.1.4 root 632:
1.1 root 633: n5 = (n6 >> 8) & 0xff;
634: n6 &= 0xff;
1.1.1.4 root 635:
1.1 root 636: laddr = ntohl(so->so_faddr.s_addr);
1.1.1.4 root 637:
1.1 root 638: n1 = ((laddr >> 24) & 0xff);
639: n2 = ((laddr >> 16) & 0xff);
640: n3 = ((laddr >> 8) & 0xff);
641: n4 = (laddr & 0xff);
1.1.1.4 root 642:
1.1 root 643: m->m_len = bptr - m->m_data; /* Adjust length */
1.1.1.5 root 644: m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
645: "ORT %d,%d,%d,%d,%d,%d\r\n%s",
646: n1, n2, n3, n4, n5, n6, x==7?buff:"");
1.1 root 647: return 1;
648: } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
649: /*
650: * Need to emulate the PASV response
651: */
1.1.1.4 root 652: x = sscanf(bptr, "27 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n%256[^\177]",
1.1 root 653: &n1, &n2, &n3, &n4, &n5, &n6, buff);
654: if (x < 6)
655: return 1;
1.1.1.4 root 656:
1.1 root 657: laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
658: lport = htons((n5 << 8) | (n6));
1.1.1.4 root 659:
1.1.1.6 root 660: if ((so = tcp_listen(slirp, INADDR_ANY, 0, laddr,
661: lport, SS_FACCEPTONCE)) == NULL) {
1.1 root 662: return 1;
1.1.1.6 root 663: }
1.1 root 664: n6 = ntohs(so->so_fport);
1.1.1.4 root 665:
1.1 root 666: n5 = (n6 >> 8) & 0xff;
667: n6 &= 0xff;
1.1.1.4 root 668:
1.1 root 669: laddr = ntohl(so->so_faddr.s_addr);
1.1.1.4 root 670:
1.1 root 671: n1 = ((laddr >> 24) & 0xff);
672: n2 = ((laddr >> 16) & 0xff);
673: n3 = ((laddr >> 8) & 0xff);
674: n4 = (laddr & 0xff);
1.1.1.4 root 675:
1.1 root 676: m->m_len = bptr - m->m_data; /* Adjust length */
1.1.1.5 root 677: m->m_len += snprintf(bptr, m->m_hdr.mh_size - m->m_len,
678: "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
679: n1, n2, n3, n4, n5, n6, x==7?buff:"");
1.1.1.4 root 680:
1.1 root 681: return 1;
682: }
1.1.1.4 root 683:
1.1 root 684: return 1;
1.1.1.4 root 685:
1.1 root 686: case EMU_KSH:
687: /*
688: * The kshell (Kerberos rsh) and shell services both pass
689: * a local port port number to carry signals to the server
690: * and stderr to the client. It is passed at the beginning
691: * of the connection as a NUL-terminated decimal ASCII string.
692: */
693: so->so_emu = 0;
694: for (lport = 0, i = 0; i < m->m_len-1; ++i) {
695: if (m->m_data[i] < '0' || m->m_data[i] > '9')
696: return 1; /* invalid number */
697: lport *= 10;
698: lport += m->m_data[i] - '0';
699: }
700: if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
1.1.1.6 root 701: (so = tcp_listen(slirp, INADDR_ANY, 0, so->so_laddr.s_addr,
702: htons(lport), SS_FACCEPTONCE)) != NULL)
1.1.1.5 root 703: m->m_len = snprintf(m->m_data, m->m_hdr.mh_size, "%d",
704: ntohs(so->so_fport)) + 1;
1.1 root 705: return 1;
1.1.1.4 root 706:
1.1 root 707: case EMU_IRC:
708: /*
709: * Need to emulate DCC CHAT, DCC SEND and DCC MOVE
710: */
711: *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */
712: if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL)
713: return 1;
1.1.1.4 root 714:
1.1 root 715: /* The %256s is for the broken mIRC */
716: if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
1.1.1.6 root 717: if ((so = tcp_listen(slirp, INADDR_ANY, 0,
718: htonl(laddr), htons(lport),
719: SS_FACCEPTONCE)) == NULL) {
1.1 root 720: return 1;
1.1.1.6 root 721: }
1.1 root 722: m->m_len = bptr - m->m_data; /* Adjust length */
1.1.1.5 root 723: m->m_len += snprintf(bptr, m->m_hdr.mh_size,
724: "DCC CHAT chat %lu %u%c\n",
725: (unsigned long)ntohl(so->so_faddr.s_addr),
726: ntohs(so->so_fport), 1);
1.1 root 727: } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
1.1.1.6 root 728: if ((so = tcp_listen(slirp, INADDR_ANY, 0,
729: htonl(laddr), htons(lport),
730: SS_FACCEPTONCE)) == NULL) {
1.1 root 731: return 1;
1.1.1.6 root 732: }
1.1 root 733: m->m_len = bptr - m->m_data; /* Adjust length */
1.1.1.5 root 734: m->m_len += snprintf(bptr, m->m_hdr.mh_size,
735: "DCC SEND %s %lu %u %u%c\n", buff,
736: (unsigned long)ntohl(so->so_faddr.s_addr),
737: ntohs(so->so_fport), n1, 1);
1.1 root 738: } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
1.1.1.6 root 739: if ((so = tcp_listen(slirp, INADDR_ANY, 0,
740: htonl(laddr), htons(lport),
741: SS_FACCEPTONCE)) == NULL) {
1.1 root 742: return 1;
1.1.1.6 root 743: }
1.1 root 744: m->m_len = bptr - m->m_data; /* Adjust length */
1.1.1.5 root 745: m->m_len += snprintf(bptr, m->m_hdr.mh_size,
746: "DCC MOVE %s %lu %u %u%c\n", buff,
747: (unsigned long)ntohl(so->so_faddr.s_addr),
748: ntohs(so->so_fport), n1, 1);
1.1 root 749: }
750: return 1;
751:
752: case EMU_REALAUDIO:
1.1.1.4 root 753: /*
1.1 root 754: * RealAudio emulation - JP. We must try to parse the incoming
755: * data and try to find the two characters that contain the
756: * port number. Then we redirect an udp port and replace the
757: * number with the real port we got.
758: *
759: * The 1.0 beta versions of the player are not supported
760: * any more.
1.1.1.4 root 761: *
1.1 root 762: * A typical packet for player version 1.0 (release version):
1.1.1.4 root 763: *
764: * 0000:50 4E 41 00 05
1.1.1.6 root 765: * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 ........g.l.c..P
1.1 root 766: * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH
767: * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v
768: * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB
1.1.1.4 root 769: *
1.1 root 770: * Now the port number 0x1BD7 is found at offset 0x04 of the
771: * Now the port number 0x1BD7 is found at offset 0x04 of the
772: * second packet. This time we received five bytes first and
773: * then the rest. You never know how many bytes you get.
774: *
775: * A typical packet for player version 2.0 (beta):
1.1.1.4 root 776: *
1.1.1.6 root 777: * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA.............
778: * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .gux.c..Win2.0.0
1.1 root 779: * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/
780: * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas
781: * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B
1.1.1.4 root 782: *
1.1 root 783: * Port number 0x1BC1 is found at offset 0x0d.
1.1.1.4 root 784: *
1.1 root 785: * This is just a horrible switch statement. Variable ra tells
786: * us where we're going.
787: */
1.1.1.4 root 788:
1.1 root 789: bptr = m->m_data;
790: while (bptr < m->m_data + m->m_len) {
791: u_short p;
792: static int ra = 0;
1.1.1.4 root 793: char ra_tbl[4];
794:
1.1 root 795: ra_tbl[0] = 0x50;
796: ra_tbl[1] = 0x4e;
797: ra_tbl[2] = 0x41;
798: ra_tbl[3] = 0;
1.1.1.4 root 799:
1.1 root 800: switch (ra) {
801: case 0:
802: case 2:
803: case 3:
804: if (*bptr++ != ra_tbl[ra]) {
805: ra = 0;
806: continue;
807: }
808: break;
1.1.1.4 root 809:
1.1 root 810: case 1:
811: /*
812: * We may get 0x50 several times, ignore them
813: */
814: if (*bptr == 0x50) {
815: ra = 1;
816: bptr++;
817: continue;
818: } else if (*bptr++ != ra_tbl[ra]) {
819: ra = 0;
820: continue;
821: }
822: break;
1.1.1.4 root 823:
824: case 4:
825: /*
1.1 root 826: * skip version number
827: */
828: bptr++;
829: break;
1.1.1.4 root 830:
831: case 5:
1.1 root 832: /*
833: * The difference between versions 1.0 and
834: * 2.0 is here. For future versions of
835: * the player this may need to be modified.
836: */
837: if (*(bptr + 1) == 0x02)
838: bptr += 8;
839: else
840: bptr += 4;
1.1.1.4 root 841: break;
842:
1.1 root 843: case 6:
844: /* This is the field containing the port
845: * number that RA-player is listening to.
846: */
1.1.1.4 root 847: lport = (((u_char*)bptr)[0] << 8)
1.1 root 848: + ((u_char *)bptr)[1];
1.1.1.4 root 849: if (lport < 6970)
1.1 root 850: lport += 256; /* don't know why */
851: if (lport < 6970 || lport > 7170)
852: return 1; /* failed */
1.1.1.4 root 853:
1.1 root 854: /* try to get udp port between 6970 - 7170 */
855: for (p = 6970; p < 7071; p++) {
1.1.1.6 root 856: if (udp_listen(slirp, INADDR_ANY,
857: htons(p),
1.1 root 858: so->so_laddr.s_addr,
859: htons(lport),
860: SS_FACCEPTONCE)) {
861: break;
862: }
863: }
864: if (p == 7071)
865: p = 0;
866: *(u_char *)bptr++ = (p >> 8) & 0xff;
1.1.1.8 root 867: *(u_char *)bptr = p & 0xff;
1.1.1.4 root 868: ra = 0;
1.1 root 869: return 1; /* port redirected, we're done */
1.1.1.4 root 870: break;
871:
1.1 root 872: default:
1.1.1.4 root 873: ra = 0;
1.1 root 874: }
875: ra++;
876: }
1.1.1.4 root 877: return 1;
878:
1.1 root 879: default:
880: /* Ooops, not emulated, won't call tcp_emu again */
881: so->so_emu = 0;
882: return 1;
883: }
884: }
885:
886: /*
887: * Do misc. config of SLiRP while its running.
888: * Return 0 if this connections is to be closed, 1 otherwise,
889: * return 2 if this is a command-line connection
890: */
1.1.1.6 root 891: int tcp_ctl(struct socket *so)
1.1 root 892: {
1.1.1.6 root 893: Slirp *slirp = so->slirp;
894: struct sbuf *sb = &so->so_snd;
895: struct ex_list *ex_ptr;
896: int do_pty;
897:
898: DEBUG_CALL("tcp_ctl");
899: DEBUG_ARG("so = %lx", (long )so);
900:
901: if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
902: /* Check if it's pty_exec */
903: for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
904: if (ex_ptr->ex_fport == so->so_fport &&
905: so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
906: if (ex_ptr->ex_pty == 3) {
907: so->s = -1;
908: so->extra = (void *)ex_ptr->ex_exec;
909: return 1;
910: }
911: do_pty = ex_ptr->ex_pty;
1.1.1.10 root 912: DEBUG_MISC((dfd, " executing %s\n", ex_ptr->ex_exec));
1.1.1.6 root 913: return fork_exec(so, ex_ptr->ex_exec, do_pty);
914: }
915: }
916: }
917: sb->sb_cc =
918: snprintf(sb->sb_wptr, sb->sb_datalen - (sb->sb_wptr - sb->sb_data),
919: "Error: No application configured.\r\n");
920: sb->sb_wptr += sb->sb_cc;
921: return 0;
1.1 root 922: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.