/*
 *   Copyright (c) 2000-2002 David Parsons. All rights reserved.
 *   
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *  3. All advertising materials mentioning features or use of this
 *     software must display the following acknowledgement:
 *     
 *   This product includes software developed by David Parsons
 *   (orc@pell.chi.il.us)
 *
 *  4. My name may not be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *     
 *  THIS SOFTWARE IS PROVIDED BY DAVID PARSONS ``AS IS'' AND ANY
 *  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
 *  PARSONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 *  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 *  THE POSSIBILITY OF SUCH DAMAGE.
 */
#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
printhost(FILE *f, long address, long netmask, int lhs)
{
    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;

	    lhs && fprintf(f, " net");

	    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 if (!lhs)
	fprintf(f, " all");
} /* printhost */


void
print(FILE *f, char *pfx, struct chainv4 *p)
{
    if (pfx)
	fprintf(f, "%s ", pfx);
    fprintf(f, "%s", (p->action == ALLOW) ? "ALLOW" : "DENY");

    if (p->direction == IN)
	printhost(f, p->dstaddr, p->dstmask, 1);
    else
	printhost(f, p->srcaddr, p->srcmask, 1);

    printport(f, p, 0);

    fprintf(f, " %s", (p->direction == IN) ? "from" : "to");
    if (p->direction == IN)
	printhost(f, p->srcaddr, p->srcmask, 0);
    else
	printhost(f, p->dstaddr, p->dstmask, 0);

#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 */
