len = strlen(pr->hostname+8); memmove(pr->hostname, pr->hostname + 8 + len + 1, lenof(pr->hostname) - (8 + len + 1));
memmove(pr->hostname, pr->hostname + 8, len);
static int pfd_receive(Plug plug, int urgent, char *data, int len){    struct PFwdPrivate *pr = (struct PFwdPrivate *) plug;    if (pr->dynamic) {	while (len--) {	    if (pr->port >= lenof(pr->hostname)) {		if ((pr->dynamic >> 12) == 4) {		    /* Send back a SOCKS 4 error before closing. */		    char data[8];		    memset(data, 0, sizeof(data));		    data[1] = 91;      /* generic `request rejected' */		    sk_write(pr->s, data, 8);		}		pfd_close(pr->s);		return 1;	    }	    pr->hostname[pr->port++] = *data++;	    /*	     * Now check what's in the buffer to see if it's a	     * valid and complete message in the SOCKS exchange.	     */	    if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 4) &&		pr->hostname[0] == 4) {		/*		 * SOCKS 4.		 */		if (pr->dynamic == 1)		    pr->dynamic = 0x4000;		if (pr->port < 2) continue;/* don't have command code yet */		if (pr->hostname[1] != 1) {		    /* Send back a SOCKS 4 error before closing. */		    char data[8];		    memset(data, 0, sizeof(data));		    data[1] = 91;      /* generic `request rejected' */		    sk_write(pr->s, data, 8);		    pfd_close(pr->s);		    return 1;		}		if (pr->port < 8) continue;   /* haven't started username */		if (pr->hostname[pr->port-1] != 0)		    continue;	       /* haven't _finished_ username */		/*		 * Now we have a full SOCKS 4 request. Check it to		 * see if it's a SOCKS 4A request.		 */		if (pr->hostname[4] == 0 && pr->hostname[5] == 0 &&		    pr->hostname[6] == 0 && pr->hostname[7] != 0) {		    /*		     * It's SOCKS 4A. So if we haven't yet		     * collected the host name, we should continue		     * waiting for data in order to do so; if we		     * have, we can go ahead.		     */		    int len;		    if (pr->dynamic == 0x4000) {			pr->dynamic = 0x4001;			continue;		    }		    pr->hostname[0] = 0;   /* reply version code */		    pr->hostname[1] = 90;   /* request granted */		    sk_write(pr->s, pr->hostname, 8);		    pr->port = GET_16BIT_MSB_FIRST(pr->hostname+2);		    len = strlen(pr->hostname+8);		    memmove(pr->hostname, pr->hostname + 8 + len + 1,			    lenof(pr->hostname) - (8 + len + 1));		    goto connect;		} else {		    /*		     * It's SOCKS 4, which means we should format		     * the IP address into the hostname string and		     * then just go.		     */		    pr->hostname[0] = 0;   /* reply version code */		    pr->hostname[1] = 90;   /* request granted */		    sk_write(pr->s, pr->hostname, 8);		    pr->port = GET_16BIT_MSB_FIRST(pr->hostname+2);		    sprintf(pr->hostname, "%d.%d.%d.%d",			    (unsigned char)pr->hostname[4],			    (unsigned char)pr->hostname[5],			    (unsigned char)pr->hostname[6],			    (unsigned char)pr->hostname[7]);		    goto connect;		}	    }	    if ((pr->dynamic == 1 || (pr->dynamic >> 12) == 5) &&		pr->hostname[0] == 5) {		/*		 * SOCKS 5.		 */		if (pr->dynamic == 1)		    pr->dynamic = 0x5000;		if (pr->dynamic == 0x5000) {		    int i, method;		    char data[2];		    /*		     * We're receiving a set of method identifiers.		     */		    if (pr->port < 2) continue;/* no method count yet */		    if (pr->port < 2 + (unsigned char)pr->hostname[1])			continue;      /* no methods yet */		    method = 0xFF;     /* invalid */		    for (i = 0; i < (unsigned char)pr->hostname[1]; i++)			if (pr->hostname[2+i] == 0) {			    method = 0;/* no auth */			    break;			}		    data[0] = 5;		    data[1] = method;		    sk_write(pr->s, data, 2);		    pr->dynamic = 0x5001;		    pr->port = 0;      /* re-empty the buffer */		    continue;		}		if (pr->dynamic == 0x5001) {		    int atype, alen;		    if (pr->port < 6) continue;		    atype = (unsigned char)pr->hostname[3];		    if (atype == 1)    /* IPv4 address */			alen = 4;		    if (atype == 4)    /* IPv6 address */			alen = 16;		    if (atype == 3)    /* domain name has leading length */			alen = 1 + (unsigned char)pr->hostname[4];		    if (pr->port < 6 + alen) continue;		    if (pr->hostname[1] != 1 || pr->hostname[2] != 0) {			pr->hostname[1] = 1;   /* generic failure */			pr->hostname[2] = 0;   /* reserved */			sk_write(pr->s, pr->hostname, pr->port);			pfd_close(pr->s);			return 1;		    }		    /*		     * Now we have a viable connect request. Switch		     * on atype.		     */		    pr->port = GET_16BIT_MSB_FIRST(pr->hostname+4+alen);		    if (atype == 1) {			pr->hostname[1] = 0;   /* succeeded */			sk_write(pr->s, pr->hostname, alen + 6);			sprintf(pr->hostname, "%d.%d.%d.%d",				(unsigned char)pr->hostname[4],				(unsigned char)pr->hostname[5],				(unsigned char)pr->hostname[6],				(unsigned char)pr->hostname[7]);			goto connect;		    } else if (atype == 3) {			pr->hostname[1] = 0;   /* succeeded */			sk_write(pr->s, pr->hostname, alen + 6);			memmove(pr->hostname, pr->hostname + 5, alen-1);			pr->hostname[alen-1] = '\0';			goto connect;		    } else {			/*			 * Unknown address type. (FIXME: support IPv6!)			 */			pr->hostname[1] = 8;   /* atype not supported */			sk_write(pr->s, pr->hostname, pr->port);			pfd_close(pr->s);			return 1;					    }		}	    }	    	    /*	     * If we get here without either having done `continue'	     * or `goto connect', it must be because there is no	     * sensible interpretation of what's in our buffer. So	     * close the connection rudely.	     */	    pfd_close(pr->s);	    return 1;	}	return 1;	/*	 * We come here when we're ready to make an actual	 * connection.	 */	connect:	pr->c = new_sock_channel(pr->backhandle, pr->s);	if (pr->c == NULL) {	    pfd_close(pr->s);	    return 1;	} else {	    /* asks to forward to the specified host/port for this */	    ssh_send_port_open(pr->c, pr->hostname, pr->port, "forwarding");	}	pr->dynamic = 0;	/*	 * Now freeze the socket until the SSH server confirms the	 * connection.	 */	sk_set_frozen(pr->s, 1);	/*	 * If there's any data remaining in our current buffer,	 * save it to be sent on pfd_confirm().	 */	if (len > 0) {	    pr->buffer = snewn(len, char);	    memcpy(pr->buffer, data, len);	    pr->buflen = len;	}    }    if (pr->ready) {	if (sshfwd_write(pr->c, data, len) > 0) {	    pr->throttled = 1;	    sk_set_frozen(pr->s, 1);	}    }    return 1;}