epfrec->keep = TRUE;
epfrec->status = KEEP;
static void ssh_setup_portfwd(Ssh ssh, const Config *cfg){    char address_family, type;    int n;    int sport,dport,sserv,dserv;    char sports[256], dports[256], saddr[256], host[256];    const char *portfwd_strptr;    portfwd_strptr = cfg->portfwd;    if (!ssh->portfwds) {	ssh->portfwds = newtree234(ssh_portcmp);    } else {	/*	 * Go through the existing port forwardings and tag them	 * with keep==FALSE. Any that we want to keep will be	 * re-enabled as we go through the configuration and find	 * out which bits are the same as they were before.	 */	struct ssh_portfwd *epf;	int i;	for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++)	    epf->keep = FALSE;    }    while (*portfwd_strptr) {	address_family = 'A';	type = 'L';	while (*portfwd_strptr && *portfwd_strptr != '\t') {	    if (*portfwd_strptr == 'A' ||		*portfwd_strptr == '4' ||		*portfwd_strptr == '6')		address_family = *portfwd_strptr;	    else if (*portfwd_strptr == 'L' ||		*portfwd_strptr == 'R' ||		*portfwd_strptr == 'D')		type = *portfwd_strptr;	    portfwd_strptr++;	}	saddr[0] = '\0';	n = 0;	while (*portfwd_strptr && *portfwd_strptr != '\t') {	    if (*portfwd_strptr == ':') {		/*		 * We've seen a colon in the middle of the		 * source port number. This means that		 * everything we've seen until now is the		 * source _address_, so we'll move it into		 * saddr and start sports from the beginning		 * again.		 */		portfwd_strptr++;		sports[n] = '\0';		if (ssh->version == 1 && type == 'R') {		    logeventf(ssh, "SSH1 cannot handle remote source address "			      "spec \"%s\"; ignoring", sports);		} else		    strcpy(saddr, sports);		n = 0;	    }	    if (n < 255) sports[n++] = *portfwd_strptr++;	}	sports[n] = 0;	if (type != 'D') {	    if (*portfwd_strptr == '\t')		portfwd_strptr++;	    n = 0;	    while (*portfwd_strptr && *portfwd_strptr != ':') {		if (n < 255) host[n++] = *portfwd_strptr++;	    }	    host[n] = 0;	    if (*portfwd_strptr == ':')		portfwd_strptr++;	    n = 0;	    while (*portfwd_strptr) {		if (n < 255) dports[n++] = *portfwd_strptr++;	    }	    dports[n] = 0;	    portfwd_strptr++;	    dport = atoi(dports);	    dserv = 0;	    if (dport == 0) {		dserv = 1;		dport = net_service_lookup(dports);		if (!dport) {		    logeventf(ssh, "Service lookup failed for destination"			      " port \"%s\"", dports);		}	    }	} else {	    while (*portfwd_strptr) portfwd_strptr++;	    dport = dserv = -1;	    portfwd_strptr++;	       /* eat the NUL and move to next one */	}	sport = atoi(sports);	sserv = 0;	if (sport == 0) {	    sserv = 1;	    sport = net_service_lookup(sports);	    if (!sport) {		logeventf(ssh, "Service lookup failed for source"			  " port \"%s\"", sports);	    }	}	if (sport && dport) {	    /* Set up a description of the source port. */	    struct ssh_portfwd *pfrec, *epfrec;	    char *sportdesc;	    sportdesc = dupprintf("%.*s%.*s%.*s%.*s%d%.*s",				  (int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL,				  (int)(*saddr?1:0), ":",				  (int)(sserv ? strlen(sports) : 0), sports,				  sserv, "(", sport, sserv, ")");	    pfrec = snew(struct ssh_portfwd);	    pfrec->type = type;	    pfrec->saddr = *saddr ? dupstr(saddr) : NULL;	    pfrec->sport = sport;	    pfrec->daddr = dupstr(host);	    pfrec->dport = dport;	    pfrec->local = NULL;	    pfrec->remote = NULL;	    pfrec->addressfamily = (address_family == '4' ? ADDRTYPE_IPV4 :				    address_family == '6' ? ADDRTYPE_IPV6 :				    ADDRTYPE_UNSPEC);	    epfrec = add234(ssh->portfwds, pfrec);	    if (epfrec != pfrec) {		/*		 * We already have a port forwarding with precisely		 * these parameters. Hence, no need to do anything;		 * simply tag the existing one as `keep'.		 */		epfrec->keep = TRUE;		free_portfwd(pfrec);	    } else if (type == 'L') {		/* Verbose description of the destination port */		char *dportdesc = dupprintf("%s:%.*s%.*s%d%.*s",					    host,					    (int)(dserv ? strlen(dports) : 0), dports,					    dserv, "(", dport, dserv, ")");		const char *err = pfd_addforward(host, dport,						 *saddr ? saddr : NULL,						 sport, ssh, &ssh->cfg,						 &pfrec->local,						 pfrec->addressfamily);		logeventf(ssh, "Local %sport %s forward to %s%s%s",			  pfrec->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :			  pfrec->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",			  sportdesc, dportdesc,			  err ? " failed: " : "", err);		sfree(dportdesc);	    } else if (type == 'D') {		const char *err = pfd_addforward(NULL, -1,						 *saddr ? saddr : NULL,						 sport, ssh, &ssh->cfg,						 &pfrec->local,						 pfrec->addressfamily);			logeventf(ssh, "Local %sport %s SOCKS dynamic forward%s%s",				  pfrec->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :				  pfrec->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",				  sportdesc,				  err ? " setup failed: " : "", err);	    } else {		struct ssh_rportfwd *pf;		/*		 * Ensure the remote port forwardings tree exists.		 */		if (!ssh->rportfwds) {		    if (ssh->version == 1)			ssh->rportfwds = newtree234(ssh_rportcmp_ssh1);		    else			ssh->rportfwds = newtree234(ssh_rportcmp_ssh2);		}		pf = snew(struct ssh_rportfwd);		strcpy(pf->dhost, host);		pf->dport = dport;		pf->sport = sport;		if (add234(ssh->rportfwds, pf) != pf) {		    logeventf(ssh, "Duplicate remote port forwarding to %s:%d",			      host, dport);		    sfree(pf);		} else {		    logeventf(ssh, "Requesting remote port %s"			      " forward to %s:%.*s%.*s%d%.*s",			      sportdesc, host,			      (int)(dserv ? strlen(dports) : 0), dports,			      dserv, "(", dport, dserv, ")");		    pf->sportdesc = sportdesc;		    sportdesc = NULL;		    pfrec->remote = pf;		    pf->pfrec = pfrec;		    if (ssh->version == 1) {			send_packet(ssh, SSH1_CMSG_PORT_FORWARD_REQUEST,				    PKT_INT, sport,				    PKT_STR, host,				    PKT_INT, dport,				    PKT_END);			ssh_queue_handler(ssh, SSH1_SMSG_SUCCESS,					  SSH1_SMSG_FAILURE,					  ssh_rportfwd_succfail, pf);		    } else {			struct Packet *pktout;			pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST);			ssh2_pkt_addstring(pktout, "tcpip-forward");			ssh2_pkt_addbool(pktout, 1);/* want reply */			if (*saddr) {			    ssh2_pkt_addstring(pktout, saddr);			} else if (ssh->cfg.rport_acceptall) {			    ssh2_pkt_addstring(pktout, "0.0.0.0");			} else {			    ssh2_pkt_addstring(pktout, "127.0.0.1");			}			ssh2_pkt_adduint32(pktout, sport);			ssh2_pkt_send(ssh, pktout);			ssh_queue_handler(ssh, SSH2_MSG_REQUEST_SUCCESS,					  SSH2_MSG_REQUEST_FAILURE,					  ssh_rportfwd_succfail, pf);		    }		}	    }	    sfree(sportdesc);	}    }    /*     * Now go through and destroy any port forwardings which were     * not re-enabled.     */    {	struct ssh_portfwd *epf;	int i;	for (i = 0; (epf = index234(ssh->portfwds, i)) != NULL; i++)	    if (!epf->keep) {		char *message;		message = dupprintf("%s port forwarding from %s%s%d",				    epf->type == 'L' ? "local" :				    epf->type == 'R' ? "remote" : "dynamic",				    epf->saddr ? epf->saddr : "",				    epf->saddr ? ":" : "",				    epf->sport);		if (epf->type != 'D') {		    char *msg2 = dupprintf("%s to %s:%d", message,					   epf->daddr, epf->dport);		    sfree(message);		    message = msg2;		}		logeventf(ssh, "Cancelling %s", message);		sfree(message);		if (epf->remote) {		    struct ssh_rportfwd *rpf = epf->remote;		    struct Packet *pktout;		    /*		     * Cancel the port forwarding at the server		     * end.		     */		    if (ssh->version == 1) {			/*			 * We cannot cancel listening ports on the			 * server side in SSH1! There's no message			 * to support it. Instead, we simply remove			 * the rportfwd record from the local end			 * so that any connections the server tries			 * to make on it are rejected.			 */		    } else {			pktout = ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST);			ssh2_pkt_addstring(pktout, "cancel-tcpip-forward");			ssh2_pkt_addbool(pktout, 0);/* _don't_ want reply */			if (epf->saddr) {			    ssh2_pkt_addstring(pktout, epf->saddr);			} else if (ssh->cfg.rport_acceptall) {			    ssh2_pkt_addstring(pktout, "0.0.0.0");			} else {			    ssh2_pkt_addstring(pktout, "127.0.0.1");			}			ssh2_pkt_adduint32(pktout, epf->sport);			ssh2_pkt_send(ssh, pktout);		    }		    del234(ssh->rportfwds, rpf);		    free_rportfwd(rpf);		} else if (epf->local) {		    pfd_terminate(epf->local);		}		delpos234(ssh->portfwds, i);		free_portfwd(epf);		i--;		       /* so we don't skip one in the list */	    }    }}