#include "policies.h"
#include <netdb.h>
#include "parser.h"

extern int rflag;

static void
printq(FILE *f, long ip)
{
    union {
	long word;
	unsigned char c[4];
    } u;

    u.word = ip;
    fprintf(f, " %u.%u.%u.%u", u.c[0], u.c[1], u.c[2], u.c[3]);
} /* printq */


static void
printport(FILE *f, struct chainv4 *p, int idx)
{
    if (idx == 0 && (p->flag & PORT_RANGE)) {
	fprintf(f, " %s/", p->proto ? ip_proto_name(p->proto) : "*");
	if (p->nrports > 0)
	    fprintf(f, "%d-", ntohs(p->port[0]));
	if (p->nrports > 1)
	    fprintf(f, "%d", ntohs(p->port[1]));
	printport(f, p, 2);
    }
    else if (idx < p->nrports) {
	if (idx == 0) {
	    if (p->nrports == 1) {
		if ((p->proto == ICMP) && (p->port[idx] == htons(8))) {
		    fprintf(f, " ping");
		    return;
		}
		else if ((p->proto == UDP) && (p->port[idx] == htons(12))) {
		    fprintf(f, " traceroute");
		    return;
		}
	    }
	    fprintf(f, " %s/", p->proto ? ip_proto_name(p->proto) : "*");
	}
	else
	    fputc(',', f);

	fprintf(f, "%d", ntohs(p->port[idx]));
	printport(f, p, idx+1);
    }
    else if (idx == 0)
	fprintf(f, " tcp/*");
} /* printport */


void
print(FILE *f, char *pfx, struct chainv4 *p)
{
    long address, netmask;

    if (pfx)
	fprintf(f, "%s ", pfx);
    fprintf(f, "%s", (p->action == ALLOW) ? "ALLOW" : "DENY");
    printport(f, p, 0);

    fprintf(f, " %s", (p->direction == IN) ? "from" : "to");
    if (p->direction == IN) {
	address = p->srcaddr;
	netmask = p->srcmask;
    }
    else {
	address = p->dstaddr;
	netmask = p->dstmask;
    }
    if (netmask) {
	if (netmask == 0xffffffff) {
	    struct hostent *he;

	    if ((he = rflag ? gethostbyaddr((char*)&address, 4, 2) : 0))
		fprintf(f, " host %s\n", he->h_name);
	    else {
		fprintf(f, " host");
		printq(f, address);
	    }
	}
	else {
	    int i;
	    int nrbits=0, on=1;

	    printq(f, address);
	    for (i=31; i >= 0; --i) {
		if (netmask & htonl(1L<<i)) {
		    if (on)
			nrbits++;
		    else
			break;
		}
		else
		    on = 0;
	    }
	    if (i < 0)
		fprintf(f, "/%d", nrbits);
	    else
		printq(f, netmask);
	}
    }
    else
	fprintf(f, " all");
    
#define Extra(f)	(((f) & IP_FW_F_MASK) & ~ (IP_FW_F_KIND|IP_FW_F_DRNG|IP_FW_F_ACCEPT))

    if (Extra(p->flag))
	fprintf(f, " flags 0x%x", Extra(p->flag));
    fputc('\n', f);
} /* print */


void
display(FILE *f, char *pfx, struct chainv4 *head)
{
    struct chainv4 *p = head;

    if (p) {
	do {
	    print(f, pfx, p);
	    p = p->next;
	} while (p != head);
    }
} /* display */
