|
|
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. ! 13: * 3. All advertising materials mentioning features or use of this software ! 14: * must display the following acknowledgement: ! 15: * This product includes software developed by the University of ! 16: * California, Berkeley and its contributors. ! 17: * 4. Neither the name of the University nor the names of its contributors ! 18: * may be used to endorse or promote products derived from this software ! 19: * without specific prior written permission. ! 20: * ! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 31: * SUCH DAMAGE. ! 32: * ! 33: * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93 ! 34: * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp ! 35: */ ! 36: ! 37: /* ! 38: * Changes and additions relating to SLiRP ! 39: * Copyright (c) 1995 Danny Gasparovski. ! 40: * ! 41: * Please read the file COPYRIGHT for the ! 42: * terms and conditions of the copyright. ! 43: */ ! 44: ! 45: #define WANT_SYS_IOCTL_H ! 46: #include <slirp.h> ! 47: ! 48: /* patchable/settable parameters for tcp */ ! 49: int tcp_mssdflt = TCP_MSS; ! 50: int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; ! 51: int tcp_do_rfc1323 = 0; /* Don't do rfc1323 performance enhancements */ ! 52: int tcp_rcvspace; /* You may want to change this */ ! 53: int tcp_sndspace; /* Keep small if you have an error prone link */ ! 54: ! 55: /* ! 56: * Tcp initialization ! 57: */ ! 58: void ! 59: tcp_init() ! 60: { ! 61: tcp_iss = 1; /* wrong */ ! 62: tcb.so_next = tcb.so_prev = &tcb; ! 63: ! 64: /* tcp_rcvspace = our Window we advertise to the remote */ ! 65: tcp_rcvspace = TCP_RCVSPACE; ! 66: tcp_sndspace = TCP_SNDSPACE; ! 67: ! 68: /* Make sure tcp_sndspace is at least 2*MSS */ ! 69: if (tcp_sndspace < 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr))) ! 70: tcp_sndspace = 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr)); ! 71: } ! 72: ! 73: /* ! 74: * Create template to be used to send tcp packets on a connection. ! 75: * Call after host entry created, fills ! 76: * in a skeletal tcp/ip header, minimizing the amount of work ! 77: * necessary when the connection is used. ! 78: */ ! 79: /* struct tcpiphdr * */ ! 80: void ! 81: tcp_template(tp) ! 82: struct tcpcb *tp; ! 83: { ! 84: struct socket *so = tp->t_socket; ! 85: register struct tcpiphdr *n = &tp->t_template; ! 86: ! 87: n->ti_next = n->ti_prev = 0; ! 88: n->ti_x1 = 0; ! 89: n->ti_pr = IPPROTO_TCP; ! 90: n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); ! 91: n->ti_src = so->so_faddr; ! 92: n->ti_dst = so->so_laddr; ! 93: n->ti_sport = so->so_fport; ! 94: n->ti_dport = so->so_lport; ! 95: ! 96: n->ti_seq = 0; ! 97: n->ti_ack = 0; ! 98: n->ti_x2 = 0; ! 99: n->ti_off = 5; ! 100: n->ti_flags = 0; ! 101: n->ti_win = 0; ! 102: n->ti_sum = 0; ! 103: n->ti_urp = 0; ! 104: } ! 105: ! 106: /* ! 107: * Send a single message to the TCP at address specified by ! 108: * the given TCP/IP header. If m == 0, then we make a copy ! 109: * of the tcpiphdr at ti and send directly to the addressed host. ! 110: * This is used to force keep alive messages out using the TCP ! 111: * template for a connection tp->t_template. If flags are given ! 112: * then we send a message back to the TCP which originated the ! 113: * segment ti, and discard the mbuf containing it and any other ! 114: * attached mbufs. ! 115: * ! 116: * In any case the ack and sequence number of the transmitted ! 117: * segment are as specified by the parameters. ! 118: */ ! 119: void ! 120: tcp_respond(tp, ti, m, ack, seq, flags) ! 121: struct tcpcb *tp; ! 122: register struct tcpiphdr *ti; ! 123: register struct mbuf *m; ! 124: tcp_seq ack, seq; ! 125: int flags; ! 126: { ! 127: register int tlen; ! 128: int win = 0; ! 129: ! 130: DEBUG_CALL("tcp_respond"); ! 131: DEBUG_ARG("tp = %lx", (long)tp); ! 132: DEBUG_ARG("ti = %lx", (long)ti); ! 133: DEBUG_ARG("m = %lx", (long)m); ! 134: DEBUG_ARG("ack = %u", ack); ! 135: DEBUG_ARG("seq = %u", seq); ! 136: DEBUG_ARG("flags = %x", flags); ! 137: ! 138: if (tp) ! 139: win = sbspace(&tp->t_socket->so_rcv); ! 140: if (m == 0) { ! 141: if ((m = m_get()) == NULL) ! 142: return; ! 143: #ifdef TCP_COMPAT_42 ! 144: tlen = 1; ! 145: #else ! 146: tlen = 0; ! 147: #endif ! 148: m->m_data += if_maxlinkhdr; ! 149: *mtod(m, struct tcpiphdr *) = *ti; ! 150: ti = mtod(m, struct tcpiphdr *); ! 151: flags = TH_ACK; ! 152: } else { ! 153: /* ! 154: * ti points into m so the next line is just making ! 155: * the mbuf point to ti ! 156: */ ! 157: m->m_data = (caddr_t)ti; ! 158: ! 159: m->m_len = sizeof (struct tcpiphdr); ! 160: tlen = 0; ! 161: #define xchg(a,b,type) { type t; t=a; a=b; b=t; } ! 162: xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t); ! 163: xchg(ti->ti_dport, ti->ti_sport, u_int16_t); ! 164: #undef xchg ! 165: } ! 166: ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); ! 167: tlen += sizeof (struct tcpiphdr); ! 168: m->m_len = tlen; ! 169: ! 170: ti->ti_next = ti->ti_prev = 0; ! 171: ti->ti_x1 = 0; ! 172: ti->ti_seq = htonl(seq); ! 173: ti->ti_ack = htonl(ack); ! 174: ti->ti_x2 = 0; ! 175: ti->ti_off = sizeof (struct tcphdr) >> 2; ! 176: ti->ti_flags = flags; ! 177: if (tp) ! 178: ti->ti_win = htons((u_int16_t) (win >> tp->rcv_scale)); ! 179: else ! 180: ti->ti_win = htons((u_int16_t)win); ! 181: ti->ti_urp = 0; ! 182: ti->ti_sum = 0; ! 183: ti->ti_sum = cksum(m, tlen); ! 184: ((struct ip *)ti)->ip_len = tlen; ! 185: ! 186: if(flags & TH_RST) ! 187: ((struct ip *)ti)->ip_ttl = MAXTTL; ! 188: else ! 189: ((struct ip *)ti)->ip_ttl = ip_defttl; ! 190: ! 191: (void) ip_output((struct socket *)0, m); ! 192: } ! 193: ! 194: /* ! 195: * Create a new TCP control block, making an ! 196: * empty reassembly queue and hooking it to the argument ! 197: * protocol control block. ! 198: */ ! 199: struct tcpcb * ! 200: tcp_newtcpcb(so) ! 201: struct socket *so; ! 202: { ! 203: register struct tcpcb *tp; ! 204: ! 205: tp = (struct tcpcb *)malloc(sizeof(*tp)); ! 206: if (tp == NULL) ! 207: return ((struct tcpcb *)0); ! 208: ! 209: memset((char *) tp, 0, sizeof(struct tcpcb)); ! 210: tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp; ! 211: tp->t_maxseg = tcp_mssdflt; ! 212: ! 213: tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; ! 214: tp->t_socket = so; ! 215: ! 216: /* ! 217: * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no ! 218: * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives ! 219: * reasonable initial retransmit time. ! 220: */ ! 221: tp->t_srtt = TCPTV_SRTTBASE; ! 222: tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2; ! 223: tp->t_rttmin = TCPTV_MIN; ! 224: ! 225: TCPT_RANGESET(tp->t_rxtcur, ! 226: ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, ! 227: TCPTV_MIN, TCPTV_REXMTMAX); ! 228: ! 229: tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; ! 230: tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; ! 231: tp->t_state = TCPS_CLOSED; ! 232: ! 233: so->so_tcpcb = tp; ! 234: ! 235: return (tp); ! 236: } ! 237: ! 238: /* ! 239: * Drop a TCP connection, reporting ! 240: * the specified error. If connection is synchronized, ! 241: * then send a RST to peer. ! 242: */ ! 243: struct tcpcb *tcp_drop(struct tcpcb *tp, int err) ! 244: { ! 245: /* tcp_drop(tp, errno) ! 246: register struct tcpcb *tp; ! 247: int errno; ! 248: { ! 249: */ ! 250: ! 251: DEBUG_CALL("tcp_drop"); ! 252: DEBUG_ARG("tp = %lx", (long)tp); ! 253: DEBUG_ARG("errno = %d", errno); ! 254: ! 255: if (TCPS_HAVERCVDSYN(tp->t_state)) { ! 256: tp->t_state = TCPS_CLOSED; ! 257: (void) tcp_output(tp); ! 258: tcpstat.tcps_drops++; ! 259: } else ! 260: tcpstat.tcps_conndrops++; ! 261: /* if (errno == ETIMEDOUT && tp->t_softerror) ! 262: * errno = tp->t_softerror; ! 263: */ ! 264: /* so->so_error = errno; */ ! 265: return (tcp_close(tp)); ! 266: } ! 267: ! 268: /* ! 269: * Close a TCP control block: ! 270: * discard all space held by the tcp ! 271: * discard internet protocol block ! 272: * wake up any sleepers ! 273: */ ! 274: struct tcpcb * ! 275: tcp_close(tp) ! 276: register struct tcpcb *tp; ! 277: { ! 278: register struct tcpiphdr *t; ! 279: struct socket *so = tp->t_socket; ! 280: register struct mbuf *m; ! 281: ! 282: DEBUG_CALL("tcp_close"); ! 283: DEBUG_ARG("tp = %lx", (long )tp); ! 284: ! 285: /* free the reassembly queue, if any */ ! 286: t = (struct tcpiphdr *) tp->seg_next; ! 287: while (t != (struct tcpiphdr *)tp) { ! 288: t = (struct tcpiphdr *)t->ti_next; ! 289: m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)t->ti_prev); ! 290: remque_32((struct tcpiphdr *) t->ti_prev); ! 291: m_freem(m); ! 292: } ! 293: /* It's static */ ! 294: /* if (tp->t_template) ! 295: * (void) m_free(dtom(tp->t_template)); ! 296: */ ! 297: /* free(tp, M_PCB); */ ! 298: free(tp); ! 299: so->so_tcpcb = 0; ! 300: soisfdisconnected(so); ! 301: /* clobber input socket cache if we're closing the cached connection */ ! 302: if (so == tcp_last_so) ! 303: tcp_last_so = &tcb; ! 304: closesocket(so->s); ! 305: sbfree(&so->so_rcv); ! 306: sbfree(&so->so_snd); ! 307: sofree(so); ! 308: tcpstat.tcps_closed++; ! 309: return ((struct tcpcb *)0); ! 310: } ! 311: ! 312: void ! 313: tcp_drain() ! 314: { ! 315: /* XXX */ ! 316: } ! 317: ! 318: /* ! 319: * When a source quench is received, close congestion window ! 320: * to one segment. We will gradually open it again as we proceed. ! 321: */ ! 322: ! 323: #ifdef notdef ! 324: ! 325: void ! 326: tcp_quench(i, errno) ! 327: ! 328: int errno; ! 329: { ! 330: struct tcpcb *tp = intotcpcb(inp); ! 331: ! 332: if (tp) ! 333: tp->snd_cwnd = tp->t_maxseg; ! 334: } ! 335: ! 336: #endif /* notdef */ ! 337: ! 338: /* ! 339: * TCP protocol interface to socket abstraction. ! 340: */ ! 341: ! 342: /* ! 343: * User issued close, and wish to trail through shutdown states: ! 344: * if never received SYN, just forget it. If got a SYN from peer, ! 345: * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. ! 346: * If already got a FIN from peer, then almost done; go to LAST_ACK ! 347: * state. In all other cases, have already sent FIN to peer (e.g. ! 348: * after PRU_SHUTDOWN), and just have to play tedious game waiting ! 349: * for peer to send FIN or not respond to keep-alives, etc. ! 350: * We can let the user exit from the close as soon as the FIN is acked. ! 351: */ ! 352: void ! 353: tcp_sockclosed(tp) ! 354: struct tcpcb *tp; ! 355: { ! 356: ! 357: DEBUG_CALL("tcp_sockclosed"); ! 358: DEBUG_ARG("tp = %lx", (long)tp); ! 359: ! 360: switch (tp->t_state) { ! 361: ! 362: case TCPS_CLOSED: ! 363: case TCPS_LISTEN: ! 364: case TCPS_SYN_SENT: ! 365: tp->t_state = TCPS_CLOSED; ! 366: tp = tcp_close(tp); ! 367: break; ! 368: ! 369: case TCPS_SYN_RECEIVED: ! 370: case TCPS_ESTABLISHED: ! 371: tp->t_state = TCPS_FIN_WAIT_1; ! 372: break; ! 373: ! 374: case TCPS_CLOSE_WAIT: ! 375: tp->t_state = TCPS_LAST_ACK; ! 376: break; ! 377: } ! 378: /* soisfdisconnecting(tp->t_socket); */ ! 379: if (tp && tp->t_state >= TCPS_FIN_WAIT_2) ! 380: soisfdisconnected(tp->t_socket); ! 381: if (tp) ! 382: tcp_output(tp); ! 383: } ! 384: ! 385: /* ! 386: * Connect to a host on the Internet ! 387: * Called by tcp_input ! 388: * Only do a connect, the tcp fields will be set in tcp_input ! 389: * return 0 if there's a result of the connect, ! 390: * else return -1 means we're still connecting ! 391: * The return value is almost always -1 since the socket is ! 392: * nonblocking. Connect returns after the SYN is sent, and does ! 393: * not wait for ACK+SYN. ! 394: */ ! 395: int tcp_fconnect(so) ! 396: struct socket *so; ! 397: { ! 398: int ret=0; ! 399: ! 400: DEBUG_CALL("tcp_fconnect"); ! 401: DEBUG_ARG("so = %lx", (long )so); ! 402: ! 403: if( (ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0) { ! 404: int opt, s=so->s; ! 405: struct sockaddr_in addr; ! 406: ! 407: fd_nonblock(s); ! 408: opt = 1; ! 409: setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt )); ! 410: opt = 1; ! 411: setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt )); ! 412: ! 413: addr.sin_family = AF_INET; ! 414: if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { ! 415: /* It's an alias */ ! 416: switch(ntohl(so->so_faddr.s_addr) & 0xff) { ! 417: case CTL_DNS: ! 418: addr.sin_addr = dns_addr; ! 419: break; ! 420: case CTL_ALIAS: ! 421: default: ! 422: addr.sin_addr = loopback_addr; ! 423: break; ! 424: } ! 425: } else ! 426: addr.sin_addr = so->so_faddr; ! 427: addr.sin_port = so->so_fport; ! 428: ! 429: DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, " ! 430: "addr.sin_addr.s_addr=%.16s\n", ! 431: ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); ! 432: /* We don't care what port we get */ ! 433: ret = connect(s,(struct sockaddr *)&addr,sizeof (addr)); ! 434: ! 435: /* ! 436: * If it's not in progress, it failed, so we just return 0, ! 437: * without clearing SS_NOFDREF ! 438: */ ! 439: soisfconnecting(so); ! 440: } ! 441: ! 442: return(ret); ! 443: } ! 444: ! 445: /* ! 446: * Accept the socket and connect to the local-host ! 447: * ! 448: * We have a problem. The correct thing to do would be ! 449: * to first connect to the local-host, and only if the ! 450: * connection is accepted, then do an accept() here. ! 451: * But, a) we need to know who's trying to connect ! 452: * to the socket to be able to SYN the local-host, and ! 453: * b) we are already connected to the foreign host by ! 454: * the time it gets to accept(), so... We simply accept ! 455: * here and SYN the local-host. ! 456: */ ! 457: void ! 458: tcp_connect(inso) ! 459: struct socket *inso; ! 460: { ! 461: struct socket *so; ! 462: struct sockaddr_in addr; ! 463: int addrlen = sizeof(struct sockaddr_in); ! 464: struct tcpcb *tp; ! 465: int s, opt; ! 466: ! 467: DEBUG_CALL("tcp_connect"); ! 468: DEBUG_ARG("inso = %lx", (long)inso); ! 469: ! 470: /* ! 471: * If it's an SS_ACCEPTONCE socket, no need to socreate() ! 472: * another socket, just use the accept() socket. ! 473: */ ! 474: if (inso->so_state & SS_FACCEPTONCE) { ! 475: /* FACCEPTONCE already have a tcpcb */ ! 476: so = inso; ! 477: } else { ! 478: if ((so = socreate()) == NULL) { ! 479: /* If it failed, get rid of the pending connection */ ! 480: closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen)); ! 481: return; ! 482: } ! 483: if (tcp_attach(so) < 0) { ! 484: free(so); /* NOT sofree */ ! 485: return; ! 486: } ! 487: so->so_laddr = inso->so_laddr; ! 488: so->so_lport = inso->so_lport; ! 489: } ! 490: ! 491: (void) tcp_mss(sototcpcb(so), 0); ! 492: ! 493: if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) { ! 494: tcp_close(sototcpcb(so)); /* This will sofree() as well */ ! 495: return; ! 496: } ! 497: fd_nonblock(s); ! 498: opt = 1; ! 499: setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); ! 500: opt = 1; ! 501: setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); ! 502: ! 503: so->so_fport = addr.sin_port; ! 504: so->so_faddr = addr.sin_addr; ! 505: /* Translate connections from localhost to the real hostname */ ! 506: if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr) ! 507: so->so_faddr = our_addr; ! 508: ! 509: /* Close the accept() socket, set right state */ ! 510: if (inso->so_state & SS_FACCEPTONCE) { ! 511: closesocket(so->s); /* If we only accept once, close the accept() socket */ ! 512: so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */ ! 513: /* if it's not FACCEPTONCE, it's already NOFDREF */ ! 514: } ! 515: so->s = s; ! 516: ! 517: so->so_iptos = tcp_tos(so); ! 518: tp = sototcpcb(so); ! 519: ! 520: tcp_template(tp); ! 521: ! 522: /* Compute window scaling to request. */ ! 523: /* while (tp->request_r_scale < TCP_MAX_WINSHIFT && ! 524: * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) ! 525: * tp->request_r_scale++; ! 526: */ ! 527: ! 528: /* soisconnecting(so); */ /* NOFDREF used instead */ ! 529: tcpstat.tcps_connattempt++; ! 530: ! 531: tp->t_state = TCPS_SYN_SENT; ! 532: tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; ! 533: tp->iss = tcp_iss; ! 534: tcp_iss += TCP_ISSINCR/2; ! 535: tcp_sendseqinit(tp); ! 536: tcp_output(tp); ! 537: } ! 538: ! 539: /* ! 540: * Attach a TCPCB to a socket. ! 541: */ ! 542: int ! 543: tcp_attach(so) ! 544: struct socket *so; ! 545: { ! 546: if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) ! 547: return -1; ! 548: ! 549: insque(so, &tcb); ! 550: ! 551: return 0; ! 552: } ! 553: ! 554: /* ! 555: * Set the socket's type of service field ! 556: */ ! 557: struct tos_t tcptos[] = { ! 558: {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */ ! 559: {21, 21, IPTOS_LOWDELAY, EMU_FTP}, /* ftp control */ ! 560: {0, 23, IPTOS_LOWDELAY, 0}, /* telnet */ ! 561: {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */ ! 562: {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT}, /* rlogin */ ! 563: {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT}, /* shell */ ! 564: {0, 544, IPTOS_LOWDELAY, EMU_KSH}, /* kshell */ ! 565: {0, 543, IPTOS_LOWDELAY, 0}, /* klogin */ ! 566: {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */ ! 567: {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */ ! 568: {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */ ! 569: {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */ ! 570: {0, 0, 0, 0} ! 571: }; ! 572: ! 573: struct emu_t *tcpemu = 0; ! 574: ! 575: /* ! 576: * Return TOS according to the above table ! 577: */ ! 578: u_int8_t ! 579: tcp_tos(so) ! 580: struct socket *so; ! 581: { ! 582: int i = 0; ! 583: struct emu_t *emup; ! 584: ! 585: while(tcptos[i].tos) { ! 586: if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) || ! 587: (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) { ! 588: so->so_emu = tcptos[i].emu; ! 589: return tcptos[i].tos; ! 590: } ! 591: i++; ! 592: } ! 593: ! 594: /* Nope, lets see if there's a user-added one */ ! 595: for (emup = tcpemu; emup; emup = emup->next) { ! 596: if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) || ! 597: (emup->lport && (ntohs(so->so_lport) == emup->lport))) { ! 598: so->so_emu = emup->emu; ! 599: return emup->tos; ! 600: } ! 601: } ! 602: ! 603: return 0; ! 604: } ! 605: ! 606: int do_echo = -1; ! 607: ! 608: /* ! 609: * Emulate programs that try and connect to us ! 610: * This includes ftp (the data connection is ! 611: * initiated by the server) and IRC (DCC CHAT and ! 612: * DCC SEND) for now ! 613: * ! 614: * NOTE: It's possible to crash SLiRP by sending it ! 615: * unstandard strings to emulate... if this is a problem, ! 616: * more checks are needed here ! 617: * ! 618: * XXX Assumes the whole command came in one packet ! 619: * ! 620: * XXX Some ftp clients will have their TOS set to ! 621: * LOWDELAY and so Nagel will kick in. Because of this, ! 622: * we'll get the first letter, followed by the rest, so ! 623: * we simply scan for ORT instead of PORT... ! 624: * DCC doesn't have this problem because there's other stuff ! 625: * in the packet before the DCC command. ! 626: * ! 627: * Return 1 if the mbuf m is still valid and should be ! 628: * sbappend()ed ! 629: * ! 630: * NOTE: if you return 0 you MUST m_free() the mbuf! ! 631: */ ! 632: int ! 633: tcp_emu(so, m) ! 634: struct socket *so; ! 635: struct mbuf *m; ! 636: { ! 637: u_int n1, n2, n3, n4, n5, n6; ! 638: char buff[256]; ! 639: u_int32_t laddr; ! 640: u_int lport; ! 641: char *bptr; ! 642: ! 643: DEBUG_CALL("tcp_emu"); ! 644: DEBUG_ARG("so = %lx", (long)so); ! 645: DEBUG_ARG("m = %lx", (long)m); ! 646: ! 647: switch(so->so_emu) { ! 648: int x, i; ! 649: ! 650: case EMU_IDENT: ! 651: /* ! 652: * Identification protocol as per rfc-1413 ! 653: */ ! 654: ! 655: { ! 656: struct socket *tmpso; ! 657: struct sockaddr_in addr; ! 658: int addrlen = sizeof(struct sockaddr_in); ! 659: struct sbuf *so_rcv = &so->so_rcv; ! 660: ! 661: memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); ! 662: so_rcv->sb_wptr += m->m_len; ! 663: so_rcv->sb_rptr += m->m_len; ! 664: m->m_data[m->m_len] = 0; /* NULL terminate */ ! 665: if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) { ! 666: if (sscanf(so_rcv->sb_data, "%d%*[ ,]%d", &n1, &n2) == 2) { ! 667: HTONS(n1); ! 668: HTONS(n2); ! 669: /* n2 is the one on our host */ ! 670: for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { ! 671: if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr && ! 672: tmpso->so_lport == n2 && ! 673: tmpso->so_faddr.s_addr == so->so_faddr.s_addr && ! 674: tmpso->so_fport == n1) { ! 675: if (getsockname(tmpso->s, ! 676: (struct sockaddr *)&addr, &addrlen) == 0) ! 677: n2 = ntohs(addr.sin_port); ! 678: break; ! 679: } ! 680: } ! 681: } ! 682: so_rcv->sb_cc = sprintf(so_rcv->sb_data, "%d,%d\r\n", n1, n2); ! 683: so_rcv->sb_rptr = so_rcv->sb_data; ! 684: so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; ! 685: } ! 686: m_free(m); ! 687: return 0; ! 688: } ! 689: ! 690: #if 0 ! 691: case EMU_RLOGIN: ! 692: /* ! 693: * Rlogin emulation ! 694: * First we accumulate all the initial option negotiation, ! 695: * then fork_exec() rlogin according to the options ! 696: */ ! 697: { ! 698: int i, i2, n; ! 699: char *ptr; ! 700: char args[100]; ! 701: char term[100]; ! 702: struct sbuf *so_snd = &so->so_snd; ! 703: struct sbuf *so_rcv = &so->so_rcv; ! 704: ! 705: /* First check if they have a priveladged port, or too much data has arrived */ ! 706: if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || ! 707: (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { ! 708: memcpy(so_snd->sb_wptr, "Permission denied\n", 18); ! 709: so_snd->sb_wptr += 18; ! 710: so_snd->sb_cc += 18; ! 711: tcp_sockclosed(sototcpcb(so)); ! 712: m_free(m); ! 713: return 0; ! 714: } ! 715: ! 716: /* Append the current data */ ! 717: memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); ! 718: so_rcv->sb_wptr += m->m_len; ! 719: so_rcv->sb_rptr += m->m_len; ! 720: m_free(m); ! 721: ! 722: /* ! 723: * Check if we have all the initial options, ! 724: * and build argument list to rlogin while we're here ! 725: */ ! 726: n = 0; ! 727: ptr = so_rcv->sb_data; ! 728: args[0] = 0; ! 729: term[0] = 0; ! 730: while (ptr < so_rcv->sb_wptr) { ! 731: if (*ptr++ == 0) { ! 732: n++; ! 733: if (n == 2) { ! 734: sprintf(args, "rlogin -l %s %s", ! 735: ptr, inet_ntoa(so->so_faddr)); ! 736: } else if (n == 3) { ! 737: i2 = so_rcv->sb_wptr - ptr; ! 738: for (i = 0; i < i2; i++) { ! 739: if (ptr[i] == '/') { ! 740: ptr[i] = 0; ! 741: #ifdef HAVE_SETENV ! 742: sprintf(term, "%s", ptr); ! 743: #else ! 744: sprintf(term, "TERM=%s", ptr); ! 745: #endif ! 746: ptr[i] = '/'; ! 747: break; ! 748: } ! 749: } ! 750: } ! 751: } ! 752: } ! 753: ! 754: if (n != 4) ! 755: return 0; ! 756: ! 757: /* We have it, set our term variable and fork_exec() */ ! 758: #ifdef HAVE_SETENV ! 759: setenv("TERM", term, 1); ! 760: #else ! 761: putenv(term); ! 762: #endif ! 763: fork_exec(so, args, 2); ! 764: term[0] = 0; ! 765: so->so_emu = 0; ! 766: ! 767: /* And finally, send the client a 0 character */ ! 768: so_snd->sb_wptr[0] = 0; ! 769: so_snd->sb_wptr++; ! 770: so_snd->sb_cc++; ! 771: ! 772: return 0; ! 773: } ! 774: ! 775: case EMU_RSH: ! 776: /* ! 777: * rsh emulation ! 778: * First we accumulate all the initial option negotiation, ! 779: * then rsh_exec() rsh according to the options ! 780: */ ! 781: { ! 782: int n; ! 783: char *ptr; ! 784: char *user; ! 785: char *args; ! 786: struct sbuf *so_snd = &so->so_snd; ! 787: struct sbuf *so_rcv = &so->so_rcv; ! 788: ! 789: /* First check if they have a priveladged port, or too much data has arrived */ ! 790: if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || ! 791: (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { ! 792: memcpy(so_snd->sb_wptr, "Permission denied\n", 18); ! 793: so_snd->sb_wptr += 18; ! 794: so_snd->sb_cc += 18; ! 795: tcp_sockclosed(sototcpcb(so)); ! 796: m_free(m); ! 797: return 0; ! 798: } ! 799: ! 800: /* Append the current data */ ! 801: memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); ! 802: so_rcv->sb_wptr += m->m_len; ! 803: so_rcv->sb_rptr += m->m_len; ! 804: m_free(m); ! 805: ! 806: /* ! 807: * Check if we have all the initial options, ! 808: * and build argument list to rlogin while we're here ! 809: */ ! 810: n = 0; ! 811: ptr = so_rcv->sb_data; ! 812: user=""; ! 813: args=""; ! 814: if (so->extra==NULL) { ! 815: struct socket *ns; ! 816: struct tcpcb* tp; ! 817: int port=atoi(ptr); ! 818: if (port <= 0) return 0; ! 819: if (port > 1023 || port < 512) { ! 820: memcpy(so_snd->sb_wptr, "Permission denied\n", 18); ! 821: so_snd->sb_wptr += 18; ! 822: so_snd->sb_cc += 18; ! 823: tcp_sockclosed(sototcpcb(so)); ! 824: return 0; ! 825: } ! 826: if ((ns=socreate()) == NULL) ! 827: return 0; ! 828: if (tcp_attach(ns)<0) { ! 829: free(ns); ! 830: return 0; ! 831: } ! 832: ! 833: ns->so_laddr=so->so_laddr; ! 834: ns->so_lport=htons(port); ! 835: ! 836: (void) tcp_mss(sototcpcb(ns), 0); ! 837: ! 838: ns->so_faddr=so->so_faddr; ! 839: ns->so_fport=htons(IPPORT_RESERVED-1); /* Use a fake port. */ ! 840: ! 841: if (ns->so_faddr.s_addr == 0 || ! 842: ns->so_faddr.s_addr == loopback_addr.s_addr) ! 843: ns->so_faddr = our_addr; ! 844: ! 845: ns->so_iptos = tcp_tos(ns); ! 846: tp = sototcpcb(ns); ! 847: ! 848: tcp_template(tp); ! 849: ! 850: /* Compute window scaling to request. */ ! 851: /* while (tp->request_r_scale < TCP_MAX_WINSHIFT && ! 852: * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) ! 853: * tp->request_r_scale++; ! 854: */ ! 855: ! 856: /*soisfconnecting(ns);*/ ! 857: ! 858: tcpstat.tcps_connattempt++; ! 859: ! 860: tp->t_state = TCPS_SYN_SENT; ! 861: tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; ! 862: tp->iss = tcp_iss; ! 863: tcp_iss += TCP_ISSINCR/2; ! 864: tcp_sendseqinit(tp); ! 865: tcp_output(tp); ! 866: so->extra=ns; ! 867: } ! 868: while (ptr < so_rcv->sb_wptr) { ! 869: if (*ptr++ == 0) { ! 870: n++; ! 871: if (n == 2) { ! 872: user=ptr; ! 873: } else if (n == 3) { ! 874: args=ptr; ! 875: } ! 876: } ! 877: } ! 878: ! 879: if (n != 4) ! 880: return 0; ! 881: ! 882: rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args); ! 883: so->so_emu = 0; ! 884: so->extra=NULL; ! 885: ! 886: /* And finally, send the client a 0 character */ ! 887: so_snd->sb_wptr[0] = 0; ! 888: so_snd->sb_wptr++; ! 889: so_snd->sb_cc++; ! 890: ! 891: return 0; ! 892: } ! 893: ! 894: case EMU_CTL: ! 895: { ! 896: int num; ! 897: struct sbuf *so_snd = &so->so_snd; ! 898: struct sbuf *so_rcv = &so->so_rcv; ! 899: ! 900: /* ! 901: * If there is binary data here, we save it in so->so_m ! 902: */ ! 903: if (!so->so_m) { ! 904: int rxlen; ! 905: char *rxdata; ! 906: rxdata=mtod(m, char *); ! 907: for (rxlen=m->m_len; rxlen; rxlen--) { ! 908: if (*rxdata++ & 0x80) { ! 909: so->so_m = m; ! 910: return 0; ! 911: } ! 912: } ! 913: } /* if(so->so_m==NULL) */ ! 914: ! 915: /* ! 916: * Append the line ! 917: */ ! 918: sbappendsb(so_rcv, m); ! 919: ! 920: /* To avoid going over the edge of the buffer, we reset it */ ! 921: if (so_snd->sb_cc == 0) ! 922: so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data; ! 923: ! 924: /* ! 925: * A bit of a hack: ! 926: * If the first packet we get here is 1 byte long, then it ! 927: * was done in telnet character mode, therefore we must echo ! 928: * the characters as they come. Otherwise, we echo nothing, ! 929: * because in linemode, the line is already echoed ! 930: * XXX two or more control connections won't work ! 931: */ ! 932: if (do_echo == -1) { ! 933: if (m->m_len == 1) do_echo = 1; ! 934: else do_echo = 0; ! 935: } ! 936: if (do_echo) { ! 937: sbappendsb(so_snd, m); ! 938: m_free(m); ! 939: tcp_output(sototcpcb(so)); /* XXX */ ! 940: } else ! 941: m_free(m); ! 942: ! 943: num = 0; ! 944: while (num < so->so_rcv.sb_cc) { ! 945: if (*(so->so_rcv.sb_rptr + num) == '\n' || ! 946: *(so->so_rcv.sb_rptr + num) == '\r') { ! 947: int n; ! 948: ! 949: *(so_rcv->sb_rptr + num) = 0; ! 950: if (ctl_password && !ctl_password_ok) { ! 951: /* Need a password */ ! 952: if (sscanf(so_rcv->sb_rptr, "pass %256s", buff) == 1) { ! 953: if (strcmp(buff, ctl_password) == 0) { ! 954: ctl_password_ok = 1; ! 955: n = sprintf(so_snd->sb_wptr, ! 956: "Password OK.\r\n"); ! 957: goto do_prompt; ! 958: } ! 959: } ! 960: n = sprintf(so_snd->sb_wptr, ! 961: "Error: Password required, log on with \"pass PASSWORD\"\r\n"); ! 962: goto do_prompt; ! 963: } ! 964: cfg_quitting = 0; ! 965: n = do_config(so_rcv->sb_rptr, so, PRN_SPRINTF); ! 966: if (!cfg_quitting) { ! 967: /* Register the printed data */ ! 968: do_prompt: ! 969: so_snd->sb_cc += n; ! 970: so_snd->sb_wptr += n; ! 971: /* Add prompt */ ! 972: n = sprintf(so_snd->sb_wptr, "Slirp> "); ! 973: so_snd->sb_cc += n; ! 974: so_snd->sb_wptr += n; ! 975: } ! 976: /* Drop so_rcv data */ ! 977: so_rcv->sb_cc = 0; ! 978: so_rcv->sb_wptr = so_rcv->sb_rptr = so_rcv->sb_data; ! 979: tcp_output(sototcpcb(so)); /* Send the reply */ ! 980: } ! 981: num++; ! 982: } ! 983: return 0; ! 984: } ! 985: #endif ! 986: case EMU_FTP: /* ftp */ ! 987: *(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */ ! 988: if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) { ! 989: /* ! 990: * Need to emulate the PORT command ! 991: */ ! 992: x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]", ! 993: &n1, &n2, &n3, &n4, &n5, &n6, buff); ! 994: if (x < 6) ! 995: return 1; ! 996: ! 997: laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); ! 998: lport = htons((n5 << 8) | (n6)); ! 999: ! 1000: if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) ! 1001: return 1; ! 1002: ! 1003: n6 = ntohs(so->so_fport); ! 1004: ! 1005: n5 = (n6 >> 8) & 0xff; ! 1006: n6 &= 0xff; ! 1007: ! 1008: laddr = ntohl(so->so_faddr.s_addr); ! 1009: ! 1010: n1 = ((laddr >> 24) & 0xff); ! 1011: n2 = ((laddr >> 16) & 0xff); ! 1012: n3 = ((laddr >> 8) & 0xff); ! 1013: n4 = (laddr & 0xff); ! 1014: ! 1015: m->m_len = bptr - m->m_data; /* Adjust length */ ! 1016: m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s", ! 1017: n1, n2, n3, n4, n5, n6, x==7?buff:""); ! 1018: return 1; ! 1019: } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) { ! 1020: /* ! 1021: * Need to emulate the PASV response ! 1022: */ ! 1023: x = sscanf(bptr, "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%256[^\177]", ! 1024: &n1, &n2, &n3, &n4, &n5, &n6, buff); ! 1025: if (x < 6) ! 1026: return 1; ! 1027: ! 1028: laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); ! 1029: lport = htons((n5 << 8) | (n6)); ! 1030: ! 1031: if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) ! 1032: return 1; ! 1033: ! 1034: n6 = ntohs(so->so_fport); ! 1035: ! 1036: n5 = (n6 >> 8) & 0xff; ! 1037: n6 &= 0xff; ! 1038: ! 1039: laddr = ntohl(so->so_faddr.s_addr); ! 1040: ! 1041: n1 = ((laddr >> 24) & 0xff); ! 1042: n2 = ((laddr >> 16) & 0xff); ! 1043: n3 = ((laddr >> 8) & 0xff); ! 1044: n4 = (laddr & 0xff); ! 1045: ! 1046: m->m_len = bptr - m->m_data; /* Adjust length */ ! 1047: m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", ! 1048: n1, n2, n3, n4, n5, n6, x==7?buff:""); ! 1049: ! 1050: return 1; ! 1051: } ! 1052: ! 1053: return 1; ! 1054: ! 1055: case EMU_KSH: ! 1056: /* ! 1057: * The kshell (Kerberos rsh) and shell services both pass ! 1058: * a local port port number to carry signals to the server ! 1059: * and stderr to the client. It is passed at the beginning ! 1060: * of the connection as a NUL-terminated decimal ASCII string. ! 1061: */ ! 1062: so->so_emu = 0; ! 1063: for (lport = 0, i = 0; i < m->m_len-1; ++i) { ! 1064: if (m->m_data[i] < '0' || m->m_data[i] > '9') ! 1065: return 1; /* invalid number */ ! 1066: lport *= 10; ! 1067: lport += m->m_data[i] - '0'; ! 1068: } ! 1069: if (m->m_data[m->m_len-1] == '\0' && lport != 0 && ! 1070: (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL) ! 1071: m->m_len = sprintf(m->m_data, "%d", ntohs(so->so_fport))+1; ! 1072: return 1; ! 1073: ! 1074: case EMU_IRC: ! 1075: /* ! 1076: * Need to emulate DCC CHAT, DCC SEND and DCC MOVE ! 1077: */ ! 1078: *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */ ! 1079: if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL) ! 1080: return 1; ! 1081: ! 1082: /* The %256s is for the broken mIRC */ ! 1083: if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) { ! 1084: if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) ! 1085: return 1; ! 1086: ! 1087: m->m_len = bptr - m->m_data; /* Adjust length */ ! 1088: m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n", ! 1089: (unsigned long)ntohl(so->so_faddr.s_addr), ! 1090: ntohs(so->so_fport), 1); ! 1091: } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { ! 1092: if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) ! 1093: return 1; ! 1094: ! 1095: m->m_len = bptr - m->m_data; /* Adjust length */ ! 1096: m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n", ! 1097: buff, (unsigned long)ntohl(so->so_faddr.s_addr), ! 1098: ntohs(so->so_fport), n1, 1); ! 1099: } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { ! 1100: if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) ! 1101: return 1; ! 1102: ! 1103: m->m_len = bptr - m->m_data; /* Adjust length */ ! 1104: m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n", ! 1105: buff, (unsigned long)ntohl(so->so_faddr.s_addr), ! 1106: ntohs(so->so_fport), n1, 1); ! 1107: } ! 1108: return 1; ! 1109: ! 1110: case EMU_REALAUDIO: ! 1111: /* ! 1112: * RealAudio emulation - JP. We must try to parse the incoming ! 1113: * data and try to find the two characters that contain the ! 1114: * port number. Then we redirect an udp port and replace the ! 1115: * number with the real port we got. ! 1116: * ! 1117: * The 1.0 beta versions of the player are not supported ! 1118: * any more. ! 1119: * ! 1120: * A typical packet for player version 1.0 (release version): ! 1121: * ! 1122: * 0000:50 4E 41 00 05 ! 1123: * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....�..g�l�c..P ! 1124: * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH ! 1125: * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v ! 1126: * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB ! 1127: * ! 1128: * Now the port number 0x1BD7 is found at offset 0x04 of the ! 1129: * Now the port number 0x1BD7 is found at offset 0x04 of the ! 1130: * second packet. This time we received five bytes first and ! 1131: * then the rest. You never know how many bytes you get. ! 1132: * ! 1133: * A typical packet for player version 2.0 (beta): ! 1134: * ! 1135: * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........�. ! 1136: * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .gux�c..Win2.0.0 ! 1137: * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/ ! 1138: * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas ! 1139: * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B ! 1140: * ! 1141: * Port number 0x1BC1 is found at offset 0x0d. ! 1142: * ! 1143: * This is just a horrible switch statement. Variable ra tells ! 1144: * us where we're going. ! 1145: */ ! 1146: ! 1147: bptr = m->m_data; ! 1148: while (bptr < m->m_data + m->m_len) { ! 1149: u_short p; ! 1150: static int ra = 0; ! 1151: char ra_tbl[4]; ! 1152: ! 1153: ra_tbl[0] = 0x50; ! 1154: ra_tbl[1] = 0x4e; ! 1155: ra_tbl[2] = 0x41; ! 1156: ra_tbl[3] = 0; ! 1157: ! 1158: switch (ra) { ! 1159: case 0: ! 1160: case 2: ! 1161: case 3: ! 1162: if (*bptr++ != ra_tbl[ra]) { ! 1163: ra = 0; ! 1164: continue; ! 1165: } ! 1166: break; ! 1167: ! 1168: case 1: ! 1169: /* ! 1170: * We may get 0x50 several times, ignore them ! 1171: */ ! 1172: if (*bptr == 0x50) { ! 1173: ra = 1; ! 1174: bptr++; ! 1175: continue; ! 1176: } else if (*bptr++ != ra_tbl[ra]) { ! 1177: ra = 0; ! 1178: continue; ! 1179: } ! 1180: break; ! 1181: ! 1182: case 4: ! 1183: /* ! 1184: * skip version number ! 1185: */ ! 1186: bptr++; ! 1187: break; ! 1188: ! 1189: case 5: ! 1190: /* ! 1191: * The difference between versions 1.0 and ! 1192: * 2.0 is here. For future versions of ! 1193: * the player this may need to be modified. ! 1194: */ ! 1195: if (*(bptr + 1) == 0x02) ! 1196: bptr += 8; ! 1197: else ! 1198: bptr += 4; ! 1199: break; ! 1200: ! 1201: case 6: ! 1202: /* This is the field containing the port ! 1203: * number that RA-player is listening to. ! 1204: */ ! 1205: lport = (((u_char*)bptr)[0] << 8) ! 1206: + ((u_char *)bptr)[1]; ! 1207: if (lport < 6970) ! 1208: lport += 256; /* don't know why */ ! 1209: if (lport < 6970 || lport > 7170) ! 1210: return 1; /* failed */ ! 1211: ! 1212: /* try to get udp port between 6970 - 7170 */ ! 1213: for (p = 6970; p < 7071; p++) { ! 1214: if (udp_listen( htons(p), ! 1215: so->so_laddr.s_addr, ! 1216: htons(lport), ! 1217: SS_FACCEPTONCE)) { ! 1218: break; ! 1219: } ! 1220: } ! 1221: if (p == 7071) ! 1222: p = 0; ! 1223: *(u_char *)bptr++ = (p >> 8) & 0xff; ! 1224: *(u_char *)bptr++ = p & 0xff; ! 1225: ra = 0; ! 1226: return 1; /* port redirected, we're done */ ! 1227: break; ! 1228: ! 1229: default: ! 1230: ra = 0; ! 1231: } ! 1232: ra++; ! 1233: } ! 1234: return 1; ! 1235: ! 1236: default: ! 1237: /* Ooops, not emulated, won't call tcp_emu again */ ! 1238: so->so_emu = 0; ! 1239: return 1; ! 1240: } ! 1241: } ! 1242: ! 1243: /* ! 1244: * Do misc. config of SLiRP while its running. ! 1245: * Return 0 if this connections is to be closed, 1 otherwise, ! 1246: * return 2 if this is a command-line connection ! 1247: */ ! 1248: int ! 1249: tcp_ctl(so) ! 1250: struct socket *so; ! 1251: { ! 1252: struct sbuf *sb = &so->so_snd; ! 1253: int command; ! 1254: struct ex_list *ex_ptr; ! 1255: int do_pty; ! 1256: // struct socket *tmpso; ! 1257: ! 1258: DEBUG_CALL("tcp_ctl"); ! 1259: DEBUG_ARG("so = %lx", (long )so); ! 1260: ! 1261: #if 0 ! 1262: /* ! 1263: * Check if they're authorised ! 1264: */ ! 1265: if (ctl_addr.s_addr && (ctl_addr.s_addr == -1 || (so->so_laddr.s_addr != ctl_addr.s_addr))) { ! 1266: sb->sb_cc = sprintf(sb->sb_wptr,"Error: Permission denied.\r\n"); ! 1267: sb->sb_wptr += sb->sb_cc; ! 1268: return 0; ! 1269: } ! 1270: #endif ! 1271: command = (ntohl(so->so_faddr.s_addr) & 0xff); ! 1272: ! 1273: switch(command) { ! 1274: default: /* Check for exec's */ ! 1275: ! 1276: /* ! 1277: * Check if it's pty_exec ! 1278: */ ! 1279: for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { ! 1280: if (ex_ptr->ex_fport == so->so_fport && ! 1281: command == ex_ptr->ex_addr) { ! 1282: do_pty = ex_ptr->ex_pty; ! 1283: goto do_exec; ! 1284: } ! 1285: } ! 1286: ! 1287: /* ! 1288: * Nothing bound.. ! 1289: */ ! 1290: /* tcp_fconnect(so); */ ! 1291: ! 1292: /* FALLTHROUGH */ ! 1293: case CTL_ALIAS: ! 1294: sb->sb_cc = sprintf(sb->sb_wptr, ! 1295: "Error: No application configured.\r\n"); ! 1296: sb->sb_wptr += sb->sb_cc; ! 1297: return(0); ! 1298: ! 1299: do_exec: ! 1300: DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec)); ! 1301: return(fork_exec(so, ex_ptr->ex_exec, do_pty)); ! 1302: ! 1303: #if 0 ! 1304: case CTL_CMD: ! 1305: for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { ! 1306: if (tmpso->so_emu == EMU_CTL && ! 1307: !(tmpso->so_tcpcb? ! 1308: (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK)) ! 1309: :0)) { ! 1310: /* Ooops, control connection already active */ ! 1311: sb->sb_cc = sprintf(sb->sb_wptr,"Sorry, already connected.\r\n"); ! 1312: sb->sb_wptr += sb->sb_cc; ! 1313: return 0; ! 1314: } ! 1315: } ! 1316: so->so_emu = EMU_CTL; ! 1317: ctl_password_ok = 0; ! 1318: sb->sb_cc = sprintf(sb->sb_wptr, "Slirp command-line ready (type \"help\" for help).\r\nSlirp> "); ! 1319: sb->sb_wptr += sb->sb_cc; ! 1320: do_echo=-1; ! 1321: return(2); ! 1322: #endif ! 1323: } ! 1324: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.