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