Exemple #1
0
void process_dest_unreach(struct tcptable *table, char *packet,
                          char *ifname, int *nomem)
{
    struct iphdr *ip;
    struct tcphdr *tcp;
    struct tcptableent *tcpentry;

    ip = (struct iphdr *) (packet + 8);

    if (ip->protocol != IPPROTO_TCP)
        return;

    tcp = (struct tcphdr *) (packet + 8 + (ip->ihl * 4));

    /*
     * We really won't be making use of nomem here.  Timeout checking
     * won't be performed either, so we just pass NULL as the pointer
     * to the configuration structure.  in_table() will recognize this
     * and set its internal timeout variable to 0.
     */

    tcpentry = in_table(table, ip->saddr, ip->daddr,
                        ntohs(tcp->source), ntohs(tcp->dest), ifname,
                        0, NULL, nomem, NULL);

    if (tcpentry != NULL) {
        tcpentry->stat = tcpentry->oth_connection->stat = FLAG_RST;
        addtoclosedlist(table, tcpentry, nomem);
    }
}
Exemple #2
0
void process_dest_unreach(struct tcptable *table, char *packet, char *ifname)
{
	struct iphdr *ip;
	struct ip6_hdr *ip6;
	struct tcphdr *tcp;
	struct tcptableent *tcpentry;

	ip = (struct iphdr *) (packet + 8);

	/*
	 * Timeout checking won't be performed either, so we just pass 0
	 * as timeout variable.
	 */

	if (ip->version == 6) {
		ip6 = (struct ip6_hdr *) (packet + 8);
		if (ip6->ip6_nxt != IPPROTO_TCP)
			return;
		tcp = (struct tcphdr *) (packet + 48);
		struct sockaddr_storage saddr, daddr;
		sockaddr_make_ipv6(&saddr, &ip6->ip6_src);
		sockaddr_set_port(&saddr, ntohs(tcp->source));
		sockaddr_make_ipv6(&daddr, &ip6->ip6_dst);
		sockaddr_set_port(&daddr, ntohs(tcp->dest));
		tcpentry =
		    in_table(table, &saddr, &daddr, ifname, 0, NULL, 0);
	} else {
		if (ip->protocol != IPPROTO_TCP)
			return;
		tcp = (struct tcphdr *) (packet + 8 + (ip->ihl * 4));
		struct sockaddr_storage saddr, daddr;
		sockaddr_make_ipv4(&saddr, ip->saddr);
		sockaddr_set_port(&saddr, ntohs(tcp->source));
		sockaddr_make_ipv4(&daddr, ip->daddr);
		sockaddr_set_port(&daddr, ntohs(tcp->dest));
		tcpentry =
		    in_table(table, &saddr, &daddr, ifname, 0, NULL, 0);
	}

	if (tcpentry != NULL) {
		tcpentry->stat = tcpentry->oth_connection->stat = FLAG_RST;
		addtoclosedlist(table, tcpentry);
	}
}
Exemple #3
0
void updateentry(struct tcptable *table, struct tcptableent *tableentry,
		 struct tcphdr *transpacket, char *packet, int linkproto,
		 unsigned long packetlength, unsigned int bcount,
		 unsigned int fragofs, int logging, int *revlook, int rvnfd,
		 FILE *logfile)
{
	char msgstring[MSGSTRING_MAX];
	char newmacaddr[18];

	if (tableentry->s_fstat != RESOLVED) {
		tableentry->s_fstat =
		    revname(revlook, &tableentry->saddr, tableentry->s_fqdn,
			    sizeof(tableentry->s_fqdn), rvnfd);
		strcpy(tableentry->oth_connection->d_fqdn, tableentry->s_fqdn);
		tableentry->oth_connection->d_fstat = tableentry->s_fstat;
	}
	if (tableentry->d_fstat != RESOLVED) {
		tableentry->d_fstat =
		    revname(revlook, &tableentry->daddr, tableentry->d_fqdn,
			    sizeof(tableentry->d_fqdn), rvnfd);
		strcpy(tableentry->oth_connection->s_fqdn, tableentry->d_fqdn);
		tableentry->oth_connection->s_fstat = tableentry->d_fstat;
	}
	tableentry->pcount++;
	tableentry->bcount += bcount;
	tableentry->psize = packetlength;
	tableentry->spanbr += bcount;

	if (options.mac) {
		memset(newmacaddr, 0, sizeof(newmacaddr));


		/* change updateentry to take struct pkt to remove this */
		if (linkproto == ARPHRD_ETHER) {
			convmacaddr((char *) (((struct ethhdr *) packet)->
					      h_source), newmacaddr);
		} else if (linkproto == ARPHRD_FDDI) {
			convmacaddr((char *) (((struct fddihdr *) packet)->
					      saddr), newmacaddr);
		}

		if (tableentry->smacaddr[0] != '\0') {
			if (strcmp(tableentry->smacaddr, newmacaddr) != 0) {
				snprintf(msgstring, MSGSTRING_MAX,
					 "TCP; %s; from %s:%s to %s:%s: new source MAC address %s (previously %s)",
					 tableentry->ifname, tableentry->s_fqdn,
					 tableentry->s_sname,
					 tableentry->d_fqdn,
					 tableentry->d_sname, newmacaddr,
					 tableentry->smacaddr);
				writelog(logging, logfile, msgstring);
				strcpy(tableentry->smacaddr, newmacaddr);
			}
		} else
			strcpy(tableentry->smacaddr, newmacaddr);
	}

	/*
	 * If this is not the first TCP fragment, skip interpretation of the
	 * TCP header.
	 */

	if ((ntohs(fragofs) & 0x1fff) != 0) {
		tableentry->lastupdate =
		    tableentry->oth_connection->lastupdate = time(NULL);
		return;
	}
	/*
	 * At this point, we have a TCP header, and we proceed to process it.
	 */

	if (tableentry->pcount == 1) {
		if ((transpacket->syn) || (transpacket->rst))
			tableentry->partial = 0;
		else
			tableentry->partial = 1;
	}
	tableentry->win = ntohs(transpacket->window);

	tableentry->stat = 0;

	if (transpacket->syn)
		tableentry->stat |= FLAG_SYN;

	if (transpacket->ack) {
		tableentry->stat |= FLAG_ACK;

		/*
		 * The following sequences are used when the ACK is in response to
		 * a FIN (see comments for FIN below).  If the opposite direction
		 * already has its indicator set to 1 (FIN sent, not ACKed), and
		 * the incoming ACK has the same sequence number as the previously
		 * stored FIN's ack number (i.e. the ACK in response to the opposite
		 * flow's FIN), the opposite direction's state is set to 2 (FIN sent
		 * and ACKed).
		 */

		if ((tableentry->oth_connection->finsent == 1)
		    && (ntohl(transpacket->seq) ==
			tableentry->oth_connection->finack)) {
			tableentry->oth_connection->finsent = 2;

			if (logging) {
				writetcplog(logging, logfile, tableentry,
					    tableentry->psize,
					    "FIN acknowleged");
			}
		}
	}
	/*
	 * The closing sequence is similar, but not identical to the TCP close
	 * sequence described in the RFC.  This sequence is primarily cosmetic.
	 *
	 * When a FIN is sent in a direction, a state indicator is set to 1,
	 * to indicate a FIN sent, but not ACKed yet.  For comparison later,
	 * the acknowlegement number is also saved in the entry.  See comments
	 * in ACK above.
	 */

	if (transpacket->fin) {

		/*
		 * First, we check if the opposite direction has no counts, in which
		 * case we simply mark the entire connection available for reuse.
		 * This is in case packets from a machine pass an interface, but
		 * on the return, completely bypasses any interface on our machine.
		 *
		 * Q: Could such a situation really happen in practice?  I managed to
		 * do it but under *really* ridiculous circumstances.
		 *
		 * A: (as of version 2.5.0, June 2001): Yes this DOES happen in
		 * practice.  Unidirectional satellite feeds can send data straight
		 * to a remote network using you as your upstream.
		 */

		if (tableentry->oth_connection->pcount == 0)
			addtoclosedlist(table, tableentry);
		else {

			/*
			 * That aside, mark the direction as being done, and make it
			 * ready for a complete close upon receipt of an ACK.  We save
			 * the acknowlegement number for identification of the proper
			 * ACK packet when it arrives in the other direction.
			 */

			tableentry->finsent = 1;
			tableentry->finack = ntohl(transpacket->ack_seq);
		}
		if (logging) {
			char flowrate[64];
			sprintf(msgstring,
				"FIN sent; %lu packets, %lu bytes, %s",
				tableentry->pcount, tableentry->bcount,
				tcplog_flowrate_msg(tableentry, flowrate, sizeof(flowrate)));

			writetcplog(logging, logfile, tableentry,
				    tableentry->psize, msgstring);
		}
	}
	if (transpacket->rst) {
		tableentry->stat |= FLAG_RST;
		if (!(tableentry->inclosed))
			addtoclosedlist(table, tableentry);

		if (logging) {
			char flowrate1[64];
			char flowrate2[64];
			snprintf(msgstring, MSGSTRING_MAX,
				 "Connection reset; %lu packets, %lu bytes, %s; opposite direction %lu packets, %lu bytes; %s",
				 tableentry->pcount, tableentry->bcount,
				 tcplog_flowrate_msg(tableentry, flowrate1, sizeof(flowrate1)),
				 tableentry->oth_connection->pcount,
				 tableentry->oth_connection->bcount,
				 tcplog_flowrate_msg(tableentry->oth_connection, flowrate2, sizeof(flowrate2)));
			writetcplog(logging, logfile, tableentry,
				    tableentry->psize, msgstring);
		}
	}
	if (transpacket->psh)
		tableentry->stat |= FLAG_PSH;

	if (transpacket->urg)
		tableentry->stat |= FLAG_URG;

	tableentry->lastupdate = tableentry->oth_connection->lastupdate =
	    time(NULL);
	/*
	 * Shall we add this entry to the closed entry list?  If both
	 * directions have their state indicators set to 2, or one direction
	 * is set to 2, and the other 1, that's it.
	 */

	if ((!tableentry->inclosed)
	    &&
	    (((tableentry->finsent == 2)
	      && ((tableentry->oth_connection->finsent == 1)
		  || (tableentry->oth_connection->finsent == 2)))
	     || ((tableentry->oth_connection->finsent == 2)
		 && ((tableentry->finsent == 1)
		     || (tableentry->finsent == 2)))))
		addtoclosedlist(table, tableentry);

}
Exemple #4
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;
	}
}
Exemple #5
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;
    }
}