#include <stdlib.h>
#include <syslog.h>
#include "firewall.h"
#include "policies.h"
#include "parser.h"

unsigned long netmask[32] = {
    0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
    0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
    0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
    0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
    0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
    0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
    0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
    0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff,
};


#ifdef __GCC__
#define INLINE inline
#else
#define INLINE
#endif


extern int vflag;


/*
 * portmatch() matches a port against the nrports/port[] array in
 * the chainv4
 */
static int
portmatch(struct chainv4 *try, unsigned short port)
{
    int idx = 0;

    if (try->flag & PORT_RANGE) {
	if (port >= try->port[0] && port <= try->port[1])
	    return 1;
	idx += 2;
    }
    while (idx < try->nrports) {
	if (port == try->port[idx++])
	    return 1;
    }
    return 0;
} /* portmatch */


/*
 * match() is a local that attempts to match an connection against
 * a PENTRY
 */
static INLINE int
match(connection *from, connection *to, struct chainv4 *try)
{
    if (vflag) {
	syslog(LOG_DEBUG, "from: %08x ? %08x (%d), to: %08x ? %08x  (%d)",
		from->ip & try->srcmask,
		try->srcaddr,
		ntohs(from->port),
		to->ip & try->dstmask,
		try->dstaddr,
		ntohs(to->port));
    }

    if ( (from->ip & try->srcmask) != try->srcaddr)
	return 0;

    if ( (to->ip & try->dstmask) != try->dstaddr)
	return 0;

    if (portmatch(try, to->port) == 0)
	return 0;

    if (vflag)
	syslog(LOG_DEBUG, "matched!");
    return 1;
} /* match */


/*
 * allow() is the public function that checks to see if a given
 *         ip/port address is legitimate.
 */
allow(connection *from, connection *to, int inbound)
{
    int direction = inbound ? IN : OUT;
    int x;
    struct chainv4 *chain, *p;

    chain = soft_fw[ !! (direction==IN) ];

    if (chain) {
	p = chain;
	do {
	    if ( match(from,to,p) )
		return p->action;
	} while ( (p = p->next) != chain);
    }
    return 0;
} /* allow */
