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