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