Esempio n. 1
0
/* add port as an alias for the "id" connection
 * returns 0 on success,-1 on failure */
int tcpconn_add_alias(int id, int port, int proto)
{
	struct tcp_connection* c;
	unsigned hash;
	struct tcp_conn_alias* a;
	
	a=0;
	/* fix the port */
	port=port?port:((proto==PROTO_TLS)?SIPS_PORT:SIP_PORT);
	TCPCONN_LOCK;
	/* check if alias already exists */
	c=_tcpconn_find(id, 0, 0);
	if (c){
		hash=tcp_addr_hash(&c->rcv.src_ip, port);
		/* search the aliases for an already existing one */
		for (a=tcpconn_aliases_hash[hash]; a; a=a->next){
			if ( (a->parent->state!=S_CONN_BAD) && (port==a->port) &&
					(ip_addr_cmp(&c->rcv.src_ip, &a->parent->rcv.src_ip)) ){
				/* found */
				if (a->parent!=c) goto error_sec;
				else goto ok;
			}
		}
		if (c->aliases>=TCP_CON_MAX_ALIASES) goto error_aliases;
		c->con_aliases[c->aliases].parent=c;
		c->con_aliases[c->aliases].port=port;
		c->con_aliases[c->aliases].hash=hash;
		tcpconn_listadd(tcpconn_aliases_hash[hash], 
								&c->con_aliases[c->aliases], next, prev);
		c->aliases++;
	}else goto error_not_found;
ok:
	TCPCONN_UNLOCK;
#ifdef EXTRA_DEBUG
	if (a) DBG("tcpconn_add_alias: alias already present\n");
	else   DBG("tcpconn_add_alias: alias port %d for hash %d, id %d\n",
			port, hash, c->id);
#endif
	return 0;
error_aliases:
	TCPCONN_UNLOCK;
	LOG(L_ERR, "ERROR: tcpconn_add_alias: too many aliases for connection %p"
				" (%d)\n", c, c->id);
	return -1;
error_not_found:
	TCPCONN_UNLOCK;
	LOG(L_ERR, "ERROR: tcpconn_add_alias: no connection found for id %d\n",id);
	return -1;
error_sec:
	TCPCONN_UNLOCK;
	LOG(L_ERR, "ERROR: tcpconn_add_alias: possible port hijack attempt\n");
	LOG(L_ERR, "ERROR: tcpconn_add_alias: alias already present and points"
			" to another connection (%d : %d and %d : %d)\n",
			a->parent->id,  port, c->id, port);
	return -1;
}
Esempio n. 2
0
/*! \brief add port as an alias for the "id" connection
 * \return 0 on success,-1 on failure */
int tcpconn_add_alias(int id, int port, int proto)
{
	struct tcp_connection* c;
	unsigned hash;
	struct tcp_conn_alias* a;

	a=0;
	/* fix the port */
	port=port ? port : protos[proto].default_port ;
	TCPCONN_LOCK(id);
	/* check if alias already exists */
	c=_tcpconn_find(id);
	if (c){
		hash=tcp_addr_hash(&c->rcv.src_ip, port);
		/* search the aliases for an already existing one */
		for (a=TCP_PART(id).tcpconn_aliases_hash[hash]; a; a=a->next) {
			if (a->parent->state != S_CONN_BAD &&
			    port == a->port &&
			    proto == a->parent->type &&
			    ip_addr_cmp(&c->rcv.src_ip, &a->parent->rcv.src_ip)) {
				/* found */
				if (a->parent!=c) goto error_sec;
				else goto ok;
			}
		}
		if (c->aliases>=TCP_CON_MAX_ALIASES) goto error_aliases;
		c->con_aliases[c->aliases].parent=c;
		c->con_aliases[c->aliases].port=port;
		c->con_aliases[c->aliases].hash=hash;
		tcpconn_listadd(TCP_PART(id).tcpconn_aliases_hash[hash],
								&c->con_aliases[c->aliases], next, prev);
		c->aliases++;
	}else goto error_not_found;
ok:
	TCPCONN_UNLOCK(id);
#ifdef EXTRA_DEBUG
	if (a) LM_DBG("alias already present\n");
	else   LM_DBG("alias port %d for hash %d, id %d\n", port, hash, id);
#endif
	return 0;
error_aliases:
	TCPCONN_UNLOCK(id);
	LM_ERR("too many aliases for connection %p (%d)\n", c, id);
	return -1;
error_not_found:
	TCPCONN_UNLOCK(id);
	LM_ERR("no connection found for id %d\n",id);
	return -1;
error_sec:
	LM_WARN("possible port hijack attempt\n");
	LM_WARN("alias already present and points to another connection "
			"(%d : %d and %d : %d)\n", a->parent->id,  port, id, port);
	TCPCONN_UNLOCK(id);
	return -1;
}
Esempio n. 3
0
/* _tcpconn_find with locks and timeout */
struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port,
									int timeout)
{
	struct tcp_connection* c;
	TCPCONN_LOCK;
	c=_tcpconn_find(id, ip, port);
	if (c){ 
			c->refcnt++;
			c->timeout=get_ticks()+timeout;
	}
	TCPCONN_UNLOCK;
	return c;
}
Esempio n. 4
0
/* used to tune the tcp_connection attributes - not to be used inside the
   network layer, but onlu from the above layer (otherwise we may end up
   in strange deadlocks!) */
int tcp_conn_fcntl(struct receive_info *rcv, int attr, void *value)
{
	struct tcp_connection *con;

	switch (attr) {
	case DST_FCNTL_SET_LIFETIME:
		/* set connection timeout */
		TCPCONN_LOCK(rcv->proto_reserved1);
		con =_tcpconn_find(rcv->proto_reserved1);
		if (!con) {
			LM_ERR("Strange, tcp conn not found (id=%d)\n",
				rcv->proto_reserved1);
		} else {
			tcp_conn_set_lifetime( con, (int)(long)(value));
		}
		TCPCONN_UNLOCK(rcv->proto_reserved1);
		return 0;
	default:
		LM_ERR("unsupported operation %d on conn\n",attr);
		return -1;
	}
	return -1;
}
Esempio n. 5
0
/*! \brief _tcpconn_find with locks and acquire fd */
int tcp_conn_get(int id, struct ip_addr* ip, int port, enum sip_protos proto,
									struct tcp_connection** conn, int* conn_fd)
{
	struct tcp_connection* c;
	struct tcp_connection* tmp;
	struct tcp_conn_alias* a;
	unsigned hash;
	long response[2];
	int part;
	int n;
	int fd;

	if (id) {
		part = id;
		TCPCONN_LOCK(part);
		if ( (c=_tcpconn_find(part))!=NULL )
			goto found;
		TCPCONN_UNLOCK(part);
	}

	/* continue search based on IP address + port + transport */
#ifdef EXTRA_DEBUG
	LM_DBG("%d  port %d\n",id, port);
	if (ip) print_ip("tcpconn_find: ip ", ip, "\n");
#endif
	if (ip){
		hash=tcp_addr_hash(ip, port);
		for( part=0 ; part<TCP_PARTITION_SIZE ; part++ ) {
			TCPCONN_LOCK(part);
			for (a=TCP_PART(part).tcpconn_aliases_hash[hash]; a; a=a->next) {
#ifdef EXTRA_DEBUG
				LM_DBG("a=%p, c=%p, c->id=%d, alias port= %d port=%d\n",
					a, a->parent, a->parent->id, a->port,
					a->parent->rcv.src_port);
				print_ip("ip=",&a->parent->rcv.src_ip,"\n");
#endif
				c = a->parent;
				if (c->state != S_CONN_BAD &&
				    port == a->port &&
				    proto == c->type &&
				    ip_addr_cmp(ip, &c->rcv.src_ip))
					goto found;
			}
			TCPCONN_UNLOCK(part);
		}
	}

	/* not found */
	*conn = NULL;
	if (conn_fd) *conn_fd = -1;
	return 0;

found:
	c->refcnt++;
	TCPCONN_UNLOCK(part);

	LM_DBG("con found in state %d\n",c->state);

	if (c->state!=S_CONN_OK || conn_fd==NULL) {
		/* no need to acquired, just return the conn with an invalid fd */
		*conn = c;
		if (conn_fd) *conn_fd = -1;
		return 1;
	}

	if (c->proc_id == process_no) {
		LM_DBG("tcp connection found (%p) already in this process ( %d ) , fd = %d\n", c, c->proc_id, c->fd);
		/* we already have the connection in this worker's reactor, no need to acquire FD */
		*conn = c;
		*conn_fd = c->fd;
		return 1;
	}

	/* acquire the fd for this connection too */
	LM_DBG("tcp connection found (%p), acquiring fd\n", c);
	/* get the fd */
	response[0]=(long)c;
	response[1]=CONN_GET_FD;
	n=send_all(unix_tcp_sock, response, sizeof(response));
	if (n<=0){
		LM_ERR("failed to get fd(write):%s (%d)\n",
				strerror(errno), errno);
		n=-1;
		goto error;
	}
	LM_DBG("c= %p, n=%d, Usock=%d\n", c, n, unix_tcp_sock);
	tmp = c;
	n=receive_fd(unix_tcp_sock, &c, sizeof(c), &fd, MSG_WAITALL);
	if (n<=0){
		LM_ERR("failed to get fd(receive_fd):"
			" %s (%d)\n", strerror(errno), errno);
		n=-1;
		goto error;
	}
	if (c!=tmp){
		LM_CRIT("got different connection:"
			"  %p (id= %d, refcnt=%d state=%d != "
			"  %p (id= %d, refcnt=%d state=%d (n=%d)\n",
			  c,   c->id,   c->refcnt,   c->state,
			  tmp, tmp->id, tmp->refcnt, tmp->state, n
		   );
		n=-1; /* fail */
		close(fd);
		goto error;
	}
	LM_DBG("after receive_fd: c= %p n=%d fd=%d\n",c, n, fd);

	*conn = c;
	*conn_fd = fd;

	return 1;
error:
	tcpconn_put(c);
	*conn = NULL;
	*conn_fd = -1;
	return -1;
}