Exemplo n.º 1
0
struct tcp_conn *search_tcp_conn(unsigned int id, union sockaddr_union *to)
{
	struct tcp_conn *conn;
	struct ip_addr ip;
	unsigned short port;
	unsigned int hash;

	port = su_getport(to);
	su2ip_addr( &ip, to);

	/* if an ID is available, search for it */
	if (id!=0) {
		hash = tcp_hash( id, 0);
		lock_get( &hash_id_lock );
		for( conn=hash_id_conns[hash] ; conn ; conn=conn->id_next ) {
			if (conn->id == id) {
				if (conn->state==TCP_CONN_TERM)
					break;
				/* validate the connection with ip and port! */
				if ( ip_addr_cmp(&ip,&conn->rcv.src_ip) &&
				(port==conn->rcv.src_port || port==conn->port_alias) ) {
					conn->ref++;
					lock_release( &hash_id_lock );
					return conn;
				}
				/* conn id failed to match */
				break;
			}
		}
		lock_release( &hash_id_lock );
		/* conn id not found */
	}

	/* search based on destination information (ip and port) */
	hash = tcp_hash(ip.u.addr32[0],port);
	lock_get( &hash_ip_lock );
	for( conn=hash_ip_conns[hash] ; conn ; conn=conn->ip_next ) {
		if ( conn->state!=TCP_CONN_TERM && ip_addr_cmp(&ip,&conn->rcv.src_ip)
		&& (port==conn->rcv.src_port || port==conn->port_alias) ) {
			/* WARNING - take care, this is the only place where both
			 * locks are taken in the same time - be aware of dead-locks! */
			lock_get( &hash_id_lock );
			conn->ref++;
			lock_release( &hash_id_lock );
			lock_release( &hash_ip_lock );
			return conn;
		}
	}
	lock_release( &hash_ip_lock );

	return NULL;
}
Exemplo n.º 2
0
static struct tcp_sock *tcp_listen_child_sock(struct tcp_sock *tsk,
						struct tcp_segment *seg)
{
	struct sock *newsk = tcp_alloc_sock(tsk->sk.protocol);
	struct tcp_sock *newtsk = tcpsk(newsk);
	tcp_set_state(newtsk, TCP_SYN_RECV);
	newsk->sk_saddr = seg->iphdr->ip_dst;
	newsk->sk_daddr = seg->iphdr->ip_src;
	newsk->sk_sport = seg->tcphdr->dst;
	newsk->sk_dport = seg->tcphdr->src;
	/* add to establish hash table for third ACK */
	if (tcp_hash(&newtsk->sk) < 0) {
		free(newsk);
		return NULL;
	}
	/*
	 * Why to get parent reference?
	 * To avoid parent accidental release.
	 * e.g: Parent is interrupted by user
	 *      when child is pending in three-way handshake.
	 */
	newtsk->parent = get_tcp_sock(tsk);
	/* FIXME: add limit to listen queue */
	list_add(&newtsk->list, &tsk->listen_queue);
	/* reference for being listed into parent queue */
	return get_tcp_sock(newtsk);
}
Exemplo n.º 3
0
static void add_tcp_hash_entry(struct tcptable *table, struct tcptableent *entry)
{
	unsigned int hp;	/* hash position in table */
	struct tcp_hashentry *ptmp;

	hp = tcp_hash(&entry->saddr, &entry->daddr, entry->ifname);
	ptmp = xmallocz(sizeof(struct tcp_hashentry));
	/*
	 * Add backpointer from screen node to hash node for deletion later
	 * (Actually point to its predecessor coz of the header cell).
	 */

	entry->hash_node = ptmp;

	/*
	 * Update hash node and add it to list.
	 */

	ptmp->tcpnode = entry;
	ptmp->hp = hp;

	if (table->hash_table[hp] == NULL) {
		ptmp->prev_entry = NULL;
		table->hash_table[hp] = ptmp;
		ptmp->index = 1;
	}

	if (table->hash_tails[hp] != NULL) {
		table->hash_tails[hp]->next_entry = ptmp;
		ptmp->prev_entry = table->hash_tails[hp];
		ptmp->index = ptmp->prev_entry->index + 1;
	}
	table->hash_tails[hp] = ptmp;
	ptmp->next_entry = NULL;
}
Exemplo n.º 4
0
void remove_tcp_conn(struct tcp_conn *conn, int extra_ref)
{
	unsigned int h;

	/* unlink it asap */
	lock_get( &hash_id_lock );
	h = tcp_hash(conn->id,0);
	tcp_hash_rm_unsafe(conn,id,h);
	conn->ref -= extra_ref;
	lock_release( &hash_id_lock );

	lock_get( &hash_ip_lock );
	h = tcp_hash(conn->rcv.src_ip.u.addr32[0],conn->rcv.src_port);
	tcp_hash_rm_unsafe(conn,ip,h);
	lock_release( &hash_ip_lock );

	/* conn is no longer in hash (cannot be found and aquired), so if ref==0
	 * we can safely free it */
	if (conn->ref==0)
		free_tcp_conn(conn);
}
Exemplo n.º 5
0
struct tcptableent *in_table(struct tcptable *table,
			     struct sockaddr_storage *saddr,
			     struct sockaddr_storage *daddr,
			     char *ifname, int logging,
			     FILE *logfile, time_t timeout)
{
	struct tcp_hashentry *hashptr;
	unsigned int hp;

	time_t now;

	if (table->head == NULL) {
		return 0;
	}
	/*
	 * Determine hash table index for this set of addresses and ports
	 */

	hp = tcp_hash(saddr, daddr, ifname);
	hashptr = table->hash_table[hp];

	while (hashptr != NULL) {
		if (sockaddr_is_equal(&hashptr->tcpnode->saddr, saddr)
		    && sockaddr_is_equal(&hashptr->tcpnode->daddr, daddr)
		    && (strcmp(hashptr->tcpnode->ifname, ifname) == 0))
			break;

		now = time(NULL);

		/*
		 * Add the timed out entries to the closed list in case we didn't
		 * find any closed ones.
		 */

		if ((timeout > 0)
		    && ((now - hashptr->tcpnode->lastupdate) / 60 > timeout)
		    && (!(hashptr->tcpnode->inclosed))) {
			hashptr->tcpnode->timedout = 1;
			hashptr->tcpnode->oth_connection->timedout = 1;
			addtoclosedlist(table, hashptr->tcpnode);

			if (logging)
				write_timeout_log(logging, logfile,
						  hashptr->tcpnode);
		}
		hashptr = hashptr->next_entry;
	}

	if (hashptr != NULL) {	/* needed to avoid SIGSEGV */
		if ((((hashptr->tcpnode->finsent == 2)
		      && (hashptr->tcpnode->oth_connection->finsent == 2)))
		    ||
		    (((hashptr->tcpnode->stat & FLAG_RST)
		      || (hashptr->tcpnode->oth_connection->
			  stat & FLAG_RST)))) {
			return NULL;
		} else {
			return hashptr->tcpnode;
		}
	} else {
		return NULL;
	}
}
Exemplo n.º 6
0
struct tcp_conn* create_tcp_conn( int s, union sockaddr_union *src_su,
						struct socket_info *dst_si, tcp_conn_state init_state)
{
	struct tcp_conn *conn;
	int h;

	if (tcp_connections_no>=tcp_max_connections) {
		LM_ERR("maximum number of connections exceeded: %d/%d\n",
			tcp_connections_no, tcp_max_connections);
		close(s);
		return NULL;
	}
	tcp_connections_no++;  //make it atomic - FIXME

	/* allocate structure */
	conn = (struct tcp_conn*)shm_malloc(sizeof(struct tcp_conn));
	if (conn==NULL){
		LM_ERR("no more pkg memory\n");
		return NULL;
	}
	memset(conn, 0, sizeof(struct tcp_conn));

	/* init lock */
	if (lock_init(&conn->state_lock)==0){
		LM_ERR("init lock failed\n");
		goto error;
	}
	conn->state = init_state;
	conn->timeout = get_ticks() + tcp_lifetime;

	/* src info */
	conn->rcv.src_su = *src_su;
	su2ip_addr(&conn->rcv.src_ip, src_su);
	conn->rcv.src_port=su_getport(src_su);
	/* dst info */
	conn->rcv.bind_address = dst_si;
	conn->rcv.dst_ip = dst_si->address;
	conn->rcv.dst_port = dst_si->port;
	conn->rcv.proto = PROTO_TCP;

	conn->socket = s;

	LM_DBG("new tcp connection with: %s:%d\n",
		ip_addr2a(&conn->rcv.src_ip),conn->rcv.src_port);

	/* add to the hashes */
	lock_get( &hash_id_lock );
	/* refed by the hash */
	conn->ref = 1;
	conn->id = last_tcp_id;
	h = tcp_hash(conn->id,0);
	tcp_hash_add_unsafe(conn,id,h);
	lock_release( &hash_id_lock );

	lock_get( &hash_ip_lock );
	h = tcp_hash(conn->rcv.src_ip.u.addr32[0],conn->rcv.src_port);
	tcp_hash_add_unsafe(conn,ip,h);
	lock_release( &hash_ip_lock );

	return conn;
error:
	shm_free(conn);
	return NULL;
}
Exemplo n.º 7
0
struct tcptableent *in_table(struct tcptable *table, unsigned long saddr,
                             unsigned long daddr, unsigned int sport,
                             unsigned int dport, char *ifname,
                             int logging, FILE * logfile,
                             int *nomem, struct OPTIONS *opts)
{
    struct tcp_hashentry *hashptr;
    unsigned int hp;

    // int hastimeouts = 0;

    time_t now;
    time_t timeout;

    if (opts != NULL)
        timeout = opts->timeout;
    else
        timeout = 0;

    if (table->head == NULL) {
        return 0;
    }
    /*
     * Determine hash table index for this set of addresses and ports
     */

    hp = tcp_hash(saddr, sport, daddr, dport, ifname);
    hashptr = table->hash_table[hp];

    while (hashptr != NULL) {
        if ((hashptr->tcpnode->saddr.s_addr == saddr) &&
            (hashptr->tcpnode->daddr.s_addr == daddr) &&
            (hashptr->tcpnode->sport == sport) &&
            (hashptr->tcpnode->dport == dport) &&
            (strcmp(hashptr->tcpnode->ifname, ifname) == 0))
            break;

        now = time(NULL);

        /*
         * Add the timed out entries to the closed list in case we didn't
         * find any closed ones.
         */

        if ((timeout > 0)
            && ((now - hashptr->tcpnode->lastupdate) / 60 > timeout)
            && (!(hashptr->tcpnode->inclosed))) {
            hashptr->tcpnode->timedout = 1;
            hashptr->tcpnode->oth_connection->timedout = 1;
            addtoclosedlist(table, hashptr->tcpnode, nomem);
			//if (!(*nomem))
			//	hastimeouts = 1;

            if (logging)
                write_timeout_log(logging, logfile, hashptr->tcpnode,
                                  opts);
        }
        hashptr = hashptr->next_entry;
    }

    if (hashptr != NULL) {      /* needed to avoid SIGSEGV */
        if ((((hashptr->tcpnode->finsent == 2) &&
              (hashptr->tcpnode->oth_connection->finsent == 2))) ||
            (((hashptr->tcpnode->stat & FLAG_RST) ||
              (hashptr->tcpnode->oth_connection->stat & FLAG_RST)))) {
            return NULL;
        } else {
            return hashptr->tcpnode;
        }
    } else {
        return NULL;
    }
}