1994-10-28 15:06:53 +00:00
|
|
|
/*
|
1996-08-13 19:43:24 +00:00
|
|
|
* Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
|
1994-10-28 15:06:53 +00:00
|
|
|
* Copyright (c) 1994 Ugen J.S.Antsilevich
|
1996-08-13 19:43:24 +00:00
|
|
|
*
|
1994-11-16 10:18:18 +00:00
|
|
|
* Idea and grammar partially left from:
|
|
|
|
* Copyright (c) 1993 Daniel Boulet
|
1994-10-28 15:06:53 +00:00
|
|
|
*
|
|
|
|
* Redistribution and use in source forms, with and without modification,
|
|
|
|
* are permitted provided that this entire comment appears intact.
|
|
|
|
*
|
|
|
|
* Redistribution in binary form may occur without any restrictions.
|
|
|
|
* Obviously, it would be nice if you gave credit where credit is due
|
|
|
|
* but requiring it would be too onerous.
|
|
|
|
*
|
|
|
|
* This software is provided ``AS IS'' without any warranties of any kind.
|
|
|
|
*
|
1994-11-16 10:18:18 +00:00
|
|
|
* NEW command line interface for IP firewall facility
|
1995-08-22 00:38:02 +00:00
|
|
|
*
|
1994-10-28 15:06:53 +00:00
|
|
|
*/
|
|
|
|
|
1999-05-29 08:12:38 +00:00
|
|
|
#ifndef lint
|
|
|
|
static const char rcsid[] =
|
1999-08-28 00:22:10 +00:00
|
|
|
"$FreeBSD$";
|
1999-05-29 08:12:38 +00:00
|
|
|
#endif /* not lint */
|
1999-06-11 09:43:53 +00:00
|
|
|
|
1999-05-29 08:12:38 +00:00
|
|
|
|
2000-05-01 20:19:44 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/mbuf.h>
|
1996-12-10 17:11:53 +00:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/sockio.h>
|
1999-08-01 16:57:24 +00:00
|
|
|
#include <sys/sysctl.h>
|
1996-12-10 17:11:53 +00:00
|
|
|
#include <sys/time.h>
|
1998-11-23 10:54:28 +00:00
|
|
|
#include <sys/wait.h>
|
1996-12-10 17:11:53 +00:00
|
|
|
|
1996-02-24 00:20:56 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <err.h>
|
1998-11-23 10:54:28 +00:00
|
|
|
#include <errno.h>
|
1999-06-19 18:43:33 +00:00
|
|
|
#include <grp.h>
|
1996-02-24 13:39:46 +00:00
|
|
|
#include <limits.h>
|
1996-12-10 17:11:53 +00:00
|
|
|
#include <netdb.h>
|
1999-06-19 18:43:33 +00:00
|
|
|
#include <pwd.h>
|
1998-11-23 10:54:28 +00:00
|
|
|
#include <signal.h>
|
1996-12-10 17:11:53 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
1997-06-02 05:02:37 +00:00
|
|
|
#include <stdarg.h>
|
1996-12-10 17:11:53 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
1999-05-29 08:12:38 +00:00
|
|
|
#include <sysexits.h>
|
1996-12-10 17:11:53 +00:00
|
|
|
|
1996-10-17 01:05:03 +00:00
|
|
|
#include <net/if.h>
|
1994-10-28 15:06:53 +00:00
|
|
|
#include <netinet/in.h>
|
1997-06-02 05:02:37 +00:00
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
#include <netinet/ip_icmp.h>
|
1996-02-24 13:39:46 +00:00
|
|
|
#include <netinet/ip_fw.h>
|
1998-12-14 18:43:03 +00:00
|
|
|
#include <net/route.h> /* def. of struct route */
|
|
|
|
#include <netinet/ip_dummynet.h>
|
1994-10-28 15:06:53 +00:00
|
|
|
#include <netinet/tcp.h>
|
1995-02-24 14:32:45 +00:00
|
|
|
#include <arpa/inet.h>
|
1994-11-16 10:18:18 +00:00
|
|
|
|
2001-10-29 00:37:24 +00:00
|
|
|
int s, /* main RAW socket */
|
2001-06-04 23:56:26 +00:00
|
|
|
do_resolv, /* Would try to resolve all */
|
2001-10-29 00:37:24 +00:00
|
|
|
do_acct, /* Show packet/byte count */
|
|
|
|
do_time, /* Show time stamps */
|
|
|
|
do_quiet, /* Be quiet in add and flush */
|
2001-06-04 23:56:26 +00:00
|
|
|
do_force, /* Don't ask for confirmation */
|
|
|
|
do_pipe, /* this cmd refers to a pipe */
|
|
|
|
do_sort, /* field to sort results (0 = no) */
|
|
|
|
do_dynamic, /* display dynamic rules */
|
|
|
|
do_expired, /* display expired dynamic rules */
|
2000-10-11 13:02:30 +00:00
|
|
|
verbose;
|
1996-02-24 00:20:56 +00:00
|
|
|
|
1997-06-02 05:02:37 +00:00
|
|
|
struct icmpcode {
|
|
|
|
int code;
|
|
|
|
char *str;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct icmpcode icmpcodes[] = {
|
|
|
|
{ ICMP_UNREACH_NET, "net" },
|
|
|
|
{ ICMP_UNREACH_HOST, "host" },
|
|
|
|
{ ICMP_UNREACH_PROTOCOL, "protocol" },
|
|
|
|
{ ICMP_UNREACH_PORT, "port" },
|
|
|
|
{ ICMP_UNREACH_NEEDFRAG, "needfrag" },
|
|
|
|
{ ICMP_UNREACH_SRCFAIL, "srcfail" },
|
|
|
|
{ ICMP_UNREACH_NET_UNKNOWN, "net-unknown" },
|
|
|
|
{ ICMP_UNREACH_HOST_UNKNOWN, "host-unknown" },
|
|
|
|
{ ICMP_UNREACH_ISOLATED, "isolated" },
|
|
|
|
{ ICMP_UNREACH_NET_PROHIB, "net-prohib" },
|
|
|
|
{ ICMP_UNREACH_HOST_PROHIB, "host-prohib" },
|
|
|
|
{ ICMP_UNREACH_TOSNET, "tosnet" },
|
|
|
|
{ ICMP_UNREACH_TOSHOST, "toshost" },
|
|
|
|
{ ICMP_UNREACH_FILTER_PROHIB, "filter-prohib" },
|
|
|
|
{ ICMP_UNREACH_HOST_PRECEDENCE, "host-precedence" },
|
2001-10-29 00:37:24 +00:00
|
|
|
{ ICMP_UNREACH_PRECEDENCE_CUTOFF, "precedence-cutoff" },
|
1997-06-02 05:02:37 +00:00
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/*
|
|
|
|
* structure to hold flag names and associated values to be
|
|
|
|
* set in the appropriate masks.
|
|
|
|
* The last element has value=0 and the string is the error message.
|
|
|
|
*/
|
|
|
|
struct _flaglist {
|
|
|
|
char * name;
|
|
|
|
u_char value;
|
|
|
|
};
|
1998-01-07 02:23:04 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
static struct _flaglist f_tcpflags[] = {
|
2002-05-13 10:19:59 +00:00
|
|
|
{ "syn", TH_SYN },
|
|
|
|
{ "fin", TH_FIN },
|
|
|
|
{ "ack", TH_ACK },
|
|
|
|
{ "psh", TH_PUSH },
|
|
|
|
{ "rst", TH_RST },
|
|
|
|
{ "urg", TH_URG },
|
2002-05-12 20:52:21 +00:00
|
|
|
{ "tcp flag", 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct _flaglist f_tcpopts[] = {
|
|
|
|
{ "mss", IP_FW_TCPOPT_MSS },
|
|
|
|
{ "window", IP_FW_TCPOPT_WINDOW },
|
|
|
|
{ "sack", IP_FW_TCPOPT_SACK },
|
|
|
|
{ "ts", IP_FW_TCPOPT_TS },
|
|
|
|
{ "cc", IP_FW_TCPOPT_CC },
|
|
|
|
{ "tcp option", 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct _flaglist f_ipopts[] = {
|
|
|
|
{ "ssrr", IP_FW_IPOPT_SSRR},
|
|
|
|
{ "lsrr", IP_FW_IPOPT_LSRR},
|
|
|
|
{ "rr", IP_FW_IPOPT_RR},
|
|
|
|
{ "ts", IP_FW_IPOPT_TS},
|
|
|
|
{ "ip option", 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct _flaglist f_iptos[] = {
|
|
|
|
{ "lowdelay", IPTOS_LOWDELAY},
|
|
|
|
{ "throughput", IPTOS_THROUGHPUT},
|
|
|
|
{ "reliability", IPTOS_RELIABILITY},
|
|
|
|
{ "mincost", IPTOS_MINCOST},
|
|
|
|
{ "congestion", IPTOS_CE},
|
|
|
|
#if 0 /* conflicting */
|
|
|
|
{ "ecntransport", IPTOS_ECT},
|
|
|
|
#endif
|
|
|
|
{ "ip tos option", 0},
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* _s_x holds a string-int pair for various lookups. Same as _flaglist.
|
|
|
|
*/
|
|
|
|
struct _s_x {
|
|
|
|
char *s;
|
|
|
|
int x;
|
|
|
|
};
|
1994-10-28 15:06:53 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
static struct _s_x limit_masks[] = {
|
|
|
|
{"src-addr", DYN_SRC_ADDR},
|
|
|
|
{"src-port", DYN_SRC_PORT},
|
|
|
|
{"dst-addr", DYN_DST_ADDR},
|
|
|
|
{"dst-port", DYN_DST_PORT},
|
|
|
|
{NULL, 0} };
|
|
|
|
|
2002-05-13 10:19:59 +00:00
|
|
|
static struct _s_x ether_types[] = {
|
|
|
|
/*
|
|
|
|
* Note, we cannot use "-:&/" in the names because they are field
|
|
|
|
* separators in the type specifications. Also, we use s = NULL as
|
|
|
|
* end-delimiter, because a type of 0 can be legal.
|
|
|
|
*/
|
|
|
|
{ "ip", 0x0800 },
|
|
|
|
{ "ipv4", 0x0800 },
|
|
|
|
{ "ipv6", 0x86dd },
|
|
|
|
{ "arp", 0x0806 },
|
|
|
|
{ "rarp", 0x8035 },
|
|
|
|
{ "vlan", 0x8100 },
|
|
|
|
{ "loop", 0x9000 },
|
|
|
|
{ "trail", 0x1000 },
|
|
|
|
{ "at", 0x809b },
|
|
|
|
{ "atalk", 0x809b },
|
|
|
|
{ "aarp", 0x80f3 },
|
|
|
|
{ "pppoe_disc", 0x8863 },
|
|
|
|
{ "pppoe_sess", 0x8864 },
|
|
|
|
{ "ipx_8022", 0x00E0 },
|
|
|
|
{ "ipx_8023", 0x0000 },
|
|
|
|
{ "ipx_ii", 0x8137 },
|
|
|
|
{ "ipx_snap", 0x8137 },
|
|
|
|
{ "ipx", 0x8137 },
|
|
|
|
{ "ns", 0x0600 },
|
|
|
|
{ NULL, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static void show_usage(void);
|
2002-05-12 20:52:21 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* print the arrays of ports. The first two entries can be
|
|
|
|
* a range (a-b) or a port:mask pair, and they are processed
|
|
|
|
* accordingly if one of the two arguments range,mask is set.
|
|
|
|
* (they are not supposed to be both set).
|
|
|
|
*/
|
1998-09-28 22:56:37 +00:00
|
|
|
static void
|
2002-05-12 20:52:21 +00:00
|
|
|
print_ports(u_char prot, int n, u_short *ports, int range, int mask)
|
1996-06-09 23:46:22 +00:00
|
|
|
{
|
2002-05-12 20:52:21 +00:00
|
|
|
int i=0;
|
|
|
|
char comma = ' ';
|
1996-06-09 23:46:22 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
if (mask) {
|
|
|
|
printf(" %04x:%04x", ports[0], ports[1]);
|
|
|
|
i=2;
|
|
|
|
comma = ',';
|
2000-01-08 11:19:19 +00:00
|
|
|
}
|
2002-05-12 20:52:21 +00:00
|
|
|
for (; i < n; i++) {
|
|
|
|
struct servent *se = NULL;
|
|
|
|
|
|
|
|
if (do_resolv) {
|
|
|
|
struct protoent *pe = getprotobynumber(prot);
|
|
|
|
se = getservbyport(htons(ports[i]),
|
|
|
|
pe ? pe->p_name : NULL);
|
|
|
|
}
|
|
|
|
if (se)
|
|
|
|
printf("%c%s", comma, se->s_name);
|
|
|
|
else
|
|
|
|
printf("%c%d", comma, ports[i]);
|
|
|
|
if (i == 0 && range)
|
|
|
|
comma = '-';
|
|
|
|
else
|
|
|
|
comma = ',';
|
2001-06-04 23:56:26 +00:00
|
|
|
}
|
1996-06-09 23:46:22 +00:00
|
|
|
}
|
|
|
|
|
1997-06-02 05:02:37 +00:00
|
|
|
static void
|
|
|
|
print_iface(char *key, union ip_fw_if *un, int byname)
|
|
|
|
{
|
|
|
|
char ifnb[FW_IFNLEN+1];
|
|
|
|
|
|
|
|
if (byname) {
|
|
|
|
strncpy(ifnb, un->fu_via_if.name, FW_IFNLEN);
|
2001-06-04 23:56:26 +00:00
|
|
|
ifnb[FW_IFNLEN] = '\0';
|
1997-06-02 05:02:37 +00:00
|
|
|
if (un->fu_via_if.unit == -1)
|
|
|
|
printf(" %s %s*", key, ifnb);
|
2001-06-04 23:56:26 +00:00
|
|
|
else
|
1997-06-02 05:02:37 +00:00
|
|
|
printf(" %s %s%d", key, ifnb, un->fu_via_if.unit);
|
|
|
|
} else if (un->fu_via_ip.s_addr != 0) {
|
|
|
|
printf(" %s %s", key, inet_ntoa(un->fu_via_ip));
|
|
|
|
} else
|
|
|
|
printf(" %s any", key);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_reject_code(int code)
|
|
|
|
{
|
|
|
|
struct icmpcode *ic;
|
|
|
|
|
|
|
|
for (ic = icmpcodes; ic->str; ic++)
|
|
|
|
if (ic->code == code) {
|
|
|
|
printf("%s", ic->str);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
printf("%u", code);
|
|
|
|
}
|
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/*
|
|
|
|
* Returns the number of bits set (from left) in a contiguous bitmask,
|
|
|
|
* or -1 if the mask is not contiguous.
|
|
|
|
* This effectively works on masks in big-endian (network) format.
|
|
|
|
* First bit is bit 7 of the first byte -- note, for MAC addresses,
|
|
|
|
* the first bit on the wire is bit 0 of the first byte.
|
|
|
|
* len is the max length in bits.
|
2001-09-27 23:44:27 +00:00
|
|
|
*/
|
2002-05-12 20:52:21 +00:00
|
|
|
static int
|
|
|
|
contigmask(u_char *p, int len)
|
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
for (i=0; i<len ; i++)
|
|
|
|
if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */
|
|
|
|
break;
|
|
|
|
for (n=i+1; n < len; n++)
|
|
|
|
if ( (p[n/8] & (1 << (7 - (n%8)))) != 0) /* mask is not contiguous */
|
|
|
|
return -1;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* print options set/clear in the two bitmasks passed as parameters.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
printopts(char *name, u_char set, u_char clear, struct _flaglist *list)
|
|
|
|
{
|
|
|
|
char *comma="";
|
|
|
|
int i;
|
|
|
|
|
|
|
|
printf(" %s ", name);
|
|
|
|
for (i=0; list[i].value != 0; i++) {
|
|
|
|
if (set & list[i].value) {
|
|
|
|
printf("%s%s", comma, list[i].name);
|
|
|
|
comma = ",";
|
|
|
|
}
|
|
|
|
if (clear & list[i].value) {
|
|
|
|
printf("%s!%s", comma, list[i].name);
|
|
|
|
comma = ",";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_ip(struct in_addr addr, struct in_addr mask)
|
|
|
|
{
|
|
|
|
struct hostent *he = NULL;
|
|
|
|
int mb = contigmask((u_char *)&mask, 32);
|
|
|
|
|
|
|
|
if (mb == 32 && do_resolv)
|
|
|
|
he = gethostbyaddr((char *)&(addr.s_addr),
|
|
|
|
sizeof(u_long), AF_INET);
|
|
|
|
if (he != NULL) /* resolved to name */
|
|
|
|
printf("%s", he->h_name);
|
|
|
|
else if (mb == 0) /* any */
|
|
|
|
printf("any");
|
|
|
|
else { /* numeric IP followed by some kind of mask */
|
|
|
|
printf("%s", inet_ntoa(addr));
|
|
|
|
if (mb < 0)
|
|
|
|
printf(":%s", inet_ntoa(mask));
|
|
|
|
else if (mb < 32)
|
|
|
|
printf("/%d", mb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* prints a MAC address/mask pair
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
print_mac(u_char *addr, u_char *mask)
|
|
|
|
{
|
|
|
|
int l = contigmask(mask, 48);
|
|
|
|
|
|
|
|
if (l == 0)
|
|
|
|
printf(" any");
|
|
|
|
else {
|
|
|
|
printf(" %02x:%02x:%02x:%02x:%02x:%02x",
|
|
|
|
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
|
|
|
|
if (l == -1)
|
|
|
|
printf("&%02x:%02x:%02x:%02x:%02x:%02x",
|
|
|
|
mask[0], mask[1], mask[2],
|
|
|
|
mask[3], mask[4], mask[5]);
|
|
|
|
else if (l < 48)
|
|
|
|
printf("/%d", l);
|
|
|
|
}
|
|
|
|
}
|
2001-09-27 23:44:27 +00:00
|
|
|
|
1997-06-02 05:02:37 +00:00
|
|
|
static void
|
2001-06-04 23:56:26 +00:00
|
|
|
show_ipfw(struct ip_fw *chain)
|
1994-10-28 15:06:53 +00:00
|
|
|
{
|
1996-08-13 19:43:24 +00:00
|
|
|
struct protoent *pe;
|
1997-06-02 05:02:37 +00:00
|
|
|
int nsp = IP_FW_GETNSRCP(chain);
|
|
|
|
int ndp = IP_FW_GETNDSTP(chain);
|
1994-10-28 15:06:53 +00:00
|
|
|
|
1996-06-09 23:46:22 +00:00
|
|
|
if (do_resolv)
|
1999-05-29 08:12:38 +00:00
|
|
|
setservent(1/*stay open*/);
|
1994-11-16 10:18:18 +00:00
|
|
|
|
1996-02-23 15:52:28 +00:00
|
|
|
printf("%05u ", chain->fw_number);
|
1995-05-30 06:12:45 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (do_acct)
|
|
|
|
printf("%10qu %10qu ", chain->fw_pcnt, chain->fw_bcnt);
|
1994-11-16 10:18:18 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (do_time) {
|
|
|
|
if (chain->timestamp) {
|
1996-06-09 23:46:22 +00:00
|
|
|
char timestr[30];
|
2002-01-19 23:20:02 +00:00
|
|
|
time_t t = _long_to_time(chain->timestamp);
|
1996-06-09 23:46:22 +00:00
|
|
|
|
2001-10-28 20:19:14 +00:00
|
|
|
strcpy(timestr, ctime(&t));
|
1996-06-09 23:46:22 +00:00
|
|
|
*strchr(timestr, '\n') = '\0';
|
|
|
|
printf("%s ", timestr);
|
2001-06-04 23:56:26 +00:00
|
|
|
} else {
|
|
|
|
printf(" ");
|
1996-06-09 23:46:22 +00:00
|
|
|
}
|
|
|
|
}
|
2002-05-12 20:52:21 +00:00
|
|
|
|
2000-02-10 14:25:26 +00:00
|
|
|
if (chain->fw_flg == IP_FW_F_CHECK_S) {
|
|
|
|
printf("check-state\n");
|
2001-06-04 23:56:26 +00:00
|
|
|
goto done;
|
2000-02-10 14:25:26 +00:00
|
|
|
}
|
1996-06-09 23:46:22 +00:00
|
|
|
|
2000-06-18 02:48:19 +00:00
|
|
|
if (chain->fw_flg & IP_FW_F_RND_MATCH) {
|
2001-09-27 23:44:27 +00:00
|
|
|
double d = 1.0 * chain->dont_match_prob;
|
2001-06-04 23:56:26 +00:00
|
|
|
d = 1 - (d / 0x7fffffff);
|
2000-06-18 02:48:19 +00:00
|
|
|
printf("prob %f ", d);
|
|
|
|
}
|
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
switch (chain->fw_flg & IP_FW_F_COMMAND) {
|
2002-05-12 20:52:21 +00:00
|
|
|
case IP_FW_F_ACCEPT:
|
|
|
|
printf("allow");
|
|
|
|
break;
|
|
|
|
case IP_FW_F_DENY:
|
|
|
|
printf("deny");
|
|
|
|
break;
|
|
|
|
case IP_FW_F_COUNT:
|
|
|
|
printf("count");
|
|
|
|
break;
|
|
|
|
case IP_FW_F_DIVERT:
|
|
|
|
printf("divert %u", chain->fw_divert_port);
|
|
|
|
break;
|
|
|
|
case IP_FW_F_TEE:
|
|
|
|
printf("tee %u", chain->fw_divert_port);
|
|
|
|
break;
|
|
|
|
case IP_FW_F_SKIPTO:
|
|
|
|
printf("skipto %u", chain->fw_skipto_rule);
|
|
|
|
break;
|
|
|
|
case IP_FW_F_PIPE:
|
|
|
|
printf("pipe %u", chain->fw_skipto_rule);
|
|
|
|
break;
|
|
|
|
case IP_FW_F_QUEUE:
|
|
|
|
printf("queue %u", chain->fw_skipto_rule);
|
|
|
|
break;
|
|
|
|
case IP_FW_F_REJECT:
|
|
|
|
if (chain->fw_reject_code == IP_FW_REJECT_RST)
|
|
|
|
printf("reset");
|
|
|
|
else {
|
|
|
|
printf("unreach ");
|
|
|
|
print_reject_code(chain->fw_reject_code);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IP_FW_F_FWD:
|
|
|
|
printf("fwd %s", inet_ntoa(chain->fw_fwd_ip.sin_addr));
|
|
|
|
if (chain->fw_fwd_ip.sin_port)
|
|
|
|
printf(",%d", chain->fw_fwd_ip.sin_port);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
errx(EX_OSERR, "impossible");
|
1996-07-10 19:44:30 +00:00
|
|
|
}
|
1999-08-11 15:36:13 +00:00
|
|
|
|
1999-08-01 16:57:24 +00:00
|
|
|
if (chain->fw_flg & IP_FW_F_PRN) {
|
1996-02-24 00:20:56 +00:00
|
|
|
printf(" log");
|
1999-08-01 16:57:24 +00:00
|
|
|
if (chain->fw_logamount)
|
|
|
|
printf(" logamount %d", chain->fw_logamount);
|
|
|
|
}
|
1994-11-16 10:18:18 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
if (chain->fw_flg & IP_FW_F_MAC) {
|
|
|
|
u_char *addr, *mask;
|
|
|
|
u_short *type, *typemask;
|
|
|
|
int l;
|
|
|
|
|
|
|
|
printf(" MAC");
|
|
|
|
addr = (u_char *)&(chain->fw_mac_hdr);
|
|
|
|
mask = (u_char *)&(chain->fw_mac_mask);
|
|
|
|
print_mac(addr, mask); /* destination */
|
|
|
|
|
|
|
|
addr += 6;
|
|
|
|
mask += 6;
|
|
|
|
print_mac(addr, mask); /* source */
|
|
|
|
type = (u_short *)&(chain->fw_mac_type);
|
|
|
|
typemask = (u_short *)&(chain->fw_mac_mask_type);
|
|
|
|
|
|
|
|
/* type is in net format for all cases but range */
|
|
|
|
if (chain->fw_flg & IP_FW_F_SRNG)
|
|
|
|
printf(" %04x-%04x", *type, *typemask);
|
2002-05-13 10:19:59 +00:00
|
|
|
else if (ntohs(*typemask) == 0)
|
|
|
|
printf(" any");
|
2002-05-12 20:52:21 +00:00
|
|
|
else if (ntohs(*typemask) != 0xffff)
|
|
|
|
printf(" %04x&%04x", ntohs(*type), ntohs(*typemask));
|
2002-05-13 10:19:59 +00:00
|
|
|
else {
|
|
|
|
struct _s_x *p = NULL;
|
|
|
|
u_int16_t i = ntohs(*type);
|
|
|
|
if (do_resolv)
|
|
|
|
for (p = ether_types ; p->s != NULL ; p++)
|
|
|
|
if (p->x == i)
|
|
|
|
break;
|
|
|
|
if (p && p->s != NULL)
|
|
|
|
printf(" %s", p->s);
|
|
|
|
else
|
|
|
|
printf(" %04x", i);
|
|
|
|
}
|
2002-05-12 20:52:21 +00:00
|
|
|
|
|
|
|
goto do_options;
|
|
|
|
}
|
1996-08-13 19:43:24 +00:00
|
|
|
pe = getprotobynumber(chain->fw_prot);
|
|
|
|
if (pe)
|
|
|
|
printf(" %s", pe->p_name);
|
|
|
|
else
|
1997-06-02 05:02:37 +00:00
|
|
|
printf(" %u", chain->fw_prot);
|
1994-11-16 10:18:18 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
printf(" from %s", chain->fw_flg & IP_FW_F_INVSRC ? "not " : "");
|
1994-10-28 15:06:53 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
if (chain->fw_flg & IP_FW_F_SME)
|
|
|
|
printf("me");
|
|
|
|
else
|
|
|
|
print_ip(chain->fw_src, chain->fw_smsk);
|
1994-10-28 15:06:53 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP)
|
|
|
|
print_ports(chain->fw_prot, nsp, chain->fw_uar.fw_pts,
|
|
|
|
chain->fw_flg & IP_FW_F_SRNG,
|
|
|
|
chain->fw_flg & IP_FW_F_SMSK );
|
1994-10-28 15:06:53 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
printf(" to %s", chain->fw_flg & IP_FW_F_INVDST ? "not " : "");
|
|
|
|
|
|
|
|
if (chain->fw_flg & IP_FW_F_DME)
|
|
|
|
printf("me");
|
|
|
|
else
|
|
|
|
print_ip(chain->fw_dst, chain->fw_dmsk);
|
|
|
|
|
|
|
|
if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP)
|
|
|
|
print_ports(chain->fw_prot, ndp, chain->fw_uar.fw_pts+nsp,
|
|
|
|
chain->fw_flg & IP_FW_F_DRNG,
|
|
|
|
chain->fw_flg & IP_FW_F_DMSK );
|
1994-11-16 10:18:18 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
do_options:
|
1999-06-19 18:43:33 +00:00
|
|
|
if (chain->fw_flg & IP_FW_F_UID) {
|
|
|
|
struct passwd *pwd = getpwuid(chain->fw_uid);
|
|
|
|
|
|
|
|
if (pwd)
|
|
|
|
printf(" uid %s", pwd->pw_name);
|
|
|
|
else
|
|
|
|
printf(" uid %u", chain->fw_uid);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chain->fw_flg & IP_FW_F_GID) {
|
|
|
|
struct group *grp = getgrgid(chain->fw_gid);
|
|
|
|
|
|
|
|
if (grp)
|
|
|
|
printf(" gid %s", grp->gr_name);
|
|
|
|
else
|
|
|
|
printf(" gid %u", chain->fw_gid);
|
|
|
|
}
|
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (chain->fw_flg & IP_FW_F_KEEP_S) {
|
2001-10-29 00:37:24 +00:00
|
|
|
struct _s_x *p = limit_masks;
|
|
|
|
|
|
|
|
switch(chain->dyn_type) {
|
|
|
|
default:
|
|
|
|
printf(" *** unknown type ***");
|
|
|
|
break ;
|
|
|
|
case DYN_KEEP_STATE:
|
|
|
|
printf(" keep-state");
|
|
|
|
break;
|
|
|
|
case DYN_LIMIT:
|
|
|
|
printf(" limit");
|
2002-05-12 20:52:21 +00:00
|
|
|
for ( ; p->x != 0 ; p++)
|
2001-10-29 00:37:24 +00:00
|
|
|
if (chain->limit_mask & p->x)
|
|
|
|
printf(" %s", p->s);
|
2001-11-04 23:19:46 +00:00
|
|
|
printf(" %d", chain->conn_limit);
|
2001-10-29 00:37:24 +00:00
|
|
|
break ;
|
|
|
|
}
|
2001-06-04 23:56:26 +00:00
|
|
|
}
|
2002-05-12 20:52:21 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
/* Direction */
|
|
|
|
if (chain->fw_flg & IP_FW_BRIDGED)
|
|
|
|
printf(" bridged");
|
1997-06-02 05:02:37 +00:00
|
|
|
if ((chain->fw_flg & IP_FW_F_IN) && !(chain->fw_flg & IP_FW_F_OUT))
|
1996-06-29 01:28:19 +00:00
|
|
|
printf(" in");
|
1997-06-02 05:02:37 +00:00
|
|
|
if (!(chain->fw_flg & IP_FW_F_IN) && (chain->fw_flg & IP_FW_F_OUT))
|
1996-06-29 01:28:19 +00:00
|
|
|
printf(" out");
|
1996-02-24 00:20:56 +00:00
|
|
|
|
1997-06-02 05:02:37 +00:00
|
|
|
/* Handle hack for "via" backwards compatibility */
|
|
|
|
if ((chain->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
|
2002-05-12 20:52:21 +00:00
|
|
|
print_iface("via", &chain->fw_in_if,
|
|
|
|
chain->fw_flg & IP_FW_F_IIFNAME);
|
1997-06-02 05:02:37 +00:00
|
|
|
} else {
|
|
|
|
/* Receive interface specified */
|
|
|
|
if (chain->fw_flg & IP_FW_F_IIFACE)
|
|
|
|
print_iface("recv", &chain->fw_in_if,
|
|
|
|
chain->fw_flg & IP_FW_F_IIFNAME);
|
|
|
|
/* Transmit interface specified */
|
|
|
|
if (chain->fw_flg & IP_FW_F_OIFACE)
|
|
|
|
print_iface("xmit", &chain->fw_out_if,
|
|
|
|
chain->fw_flg & IP_FW_F_OIFNAME);
|
1996-02-24 00:20:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (chain->fw_flg & IP_FW_F_FRAG)
|
1996-06-29 01:28:19 +00:00
|
|
|
printf(" frag");
|
1995-10-01 21:54:05 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
if (chain->fw_ipflg & IP_FW_IF_IPOPT)
|
|
|
|
printopts("ipopt", chain->fw_ipopt, chain->fw_ipnopt,
|
|
|
|
f_ipopts);
|
1995-10-23 03:58:06 +00:00
|
|
|
|
2000-10-02 03:03:31 +00:00
|
|
|
if (chain->fw_ipflg & IP_FW_IF_IPLEN)
|
|
|
|
printf(" iplen %u", chain->fw_iplen);
|
2002-05-12 20:52:21 +00:00
|
|
|
|
2000-10-02 03:03:31 +00:00
|
|
|
if (chain->fw_ipflg & IP_FW_IF_IPID)
|
2000-10-03 11:23:29 +00:00
|
|
|
printf(" ipid %#x", chain->fw_ipid);
|
2002-05-12 20:52:21 +00:00
|
|
|
|
2001-12-21 18:43:37 +00:00
|
|
|
if (chain->fw_ipflg & IP_FW_IF_IPPRE)
|
|
|
|
printf(" ipprecedence %u", (chain->fw_iptos & 0xe0) >> 5);
|
2000-10-02 03:03:31 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
if (chain->fw_ipflg & IP_FW_IF_IPTOS)
|
|
|
|
printopts("iptos", chain->fw_iptos, chain->fw_ipntos,
|
|
|
|
f_iptos);
|
2000-10-02 03:03:31 +00:00
|
|
|
|
|
|
|
if (chain->fw_ipflg & IP_FW_IF_IPTTL)
|
|
|
|
printf(" ipttl %u", chain->fw_ipttl);
|
|
|
|
|
|
|
|
if (chain->fw_ipflg & IP_FW_IF_IPVER)
|
|
|
|
printf(" ipversion %u", chain->fw_ipver);
|
|
|
|
|
o IPFW incorrectly handled filtering in the presence of previously
reserved and now allocated TCP flags in incoming packets. This patch
stops overloading those bits in the IP firewall rules, and moves
colliding flags to a seperate field, ipflg. The IPFW userland
management tool, ipfw(8), is updated to reflect this change. New TCP
flags related to ECN are now included in tcp.h for reference, although
we don't currently implement TCP+ECN.
o To use this fix without completely rebuilding, it is sufficient to copy
ip_fw.h and tcp.h into your appropriate include directory, then rebuild
the ipfw kernel module, and ipfw tool, and install both. Note that a
mismatch between module and userland tool will result in incorrect
installation of firewall rules that may have unexpected effects. This
is an MFC candidate, following shakedown. This bug does not appear
to affect ipfilter.
Reviewed by: security-officer, billf
Reported by: Aragon Gouveia <aragon@phat.za.net>
2001-01-09 03:10:30 +00:00
|
|
|
if (chain->fw_ipflg & IP_FW_IF_TCPEST)
|
1996-04-03 13:49:10 +00:00
|
|
|
printf(" established");
|
2002-05-13 10:19:59 +00:00
|
|
|
else if (chain->fw_tcpf == TH_SYN &&
|
|
|
|
chain->fw_tcpnf == TH_ACK)
|
1996-02-24 13:39:46 +00:00
|
|
|
printf(" setup");
|
2002-05-12 20:52:21 +00:00
|
|
|
else if (chain->fw_ipflg & IP_FW_IF_TCPFLG)
|
|
|
|
printopts("tcpflags", chain->fw_tcpf, chain->fw_tcpnf,
|
|
|
|
f_tcpflags);
|
|
|
|
|
|
|
|
if (chain->fw_ipflg & IP_FW_IF_TCPOPT)
|
|
|
|
printopts("tcpoptions", chain->fw_tcpopt, chain->fw_tcpnopt,
|
|
|
|
f_tcpopts);
|
2000-06-08 15:34:51 +00:00
|
|
|
|
2000-10-02 03:03:31 +00:00
|
|
|
if (chain->fw_ipflg & IP_FW_IF_TCPSEQ)
|
2001-04-05 07:37:55 +00:00
|
|
|
printf(" tcpseq %lu", (u_long)ntohl(chain->fw_tcpseq));
|
2000-10-02 03:03:31 +00:00
|
|
|
if (chain->fw_ipflg & IP_FW_IF_TCPACK)
|
2001-04-05 07:37:55 +00:00
|
|
|
printf(" tcpack %lu", (u_long)ntohl(chain->fw_tcpack));
|
2000-10-02 03:03:31 +00:00
|
|
|
if (chain->fw_ipflg & IP_FW_IF_TCPWIN)
|
|
|
|
printf(" tcpwin %hu", ntohs(chain->fw_tcpwin));
|
|
|
|
|
1996-06-09 23:46:22 +00:00
|
|
|
if (chain->fw_flg & IP_FW_F_ICMPBIT) {
|
2001-06-04 23:56:26 +00:00
|
|
|
int i, first = 1;
|
|
|
|
unsigned j;
|
1996-06-09 23:46:22 +00:00
|
|
|
|
|
|
|
printf(" icmptype");
|
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
for (i = 0; i < IP_FW_ICMPTYPES_DIM; ++i)
|
|
|
|
for (j = 0; j < sizeof(unsigned) * 8; ++j)
|
|
|
|
if (chain->fw_uar.fw_icmptypes[i] & (1 << j)) {
|
2001-08-06 13:03:38 +00:00
|
|
|
printf("%c%d", first ? ' ' : ',',
|
|
|
|
i * sizeof(unsigned) * 8 + j);
|
2001-06-04 23:56:26 +00:00
|
|
|
first = 0;
|
|
|
|
}
|
1996-06-09 23:46:22 +00:00
|
|
|
}
|
1994-11-16 10:18:18 +00:00
|
|
|
printf("\n");
|
2000-02-10 14:25:26 +00:00
|
|
|
done:
|
1996-06-09 23:46:22 +00:00
|
|
|
if (do_resolv)
|
|
|
|
endservent();
|
1994-10-28 15:06:53 +00:00
|
|
|
}
|
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
static void
|
|
|
|
show_dyn_ipfw(struct ipfw_dyn_rule *d)
|
|
|
|
{
|
|
|
|
struct protoent *pe;
|
|
|
|
struct in_addr a;
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (!d->expire && !do_expired)
|
|
|
|
return;
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-09-20 13:52:49 +00:00
|
|
|
printf("%05d %qu %qu (T %ds, slot %d)",
|
2002-05-12 20:52:21 +00:00
|
|
|
(int)(d->rule), d->pcnt, d->bcnt, d->expire, d->bucket);
|
2001-09-20 13:52:49 +00:00
|
|
|
switch (d->dyn_type) {
|
2001-09-27 23:44:27 +00:00
|
|
|
case DYN_LIMIT_PARENT:
|
2002-05-12 20:52:21 +00:00
|
|
|
printf(" PARENT %d", d->count);
|
|
|
|
break;
|
2001-09-27 23:44:27 +00:00
|
|
|
case DYN_LIMIT:
|
2002-05-12 20:52:21 +00:00
|
|
|
printf(" LIMIT");
|
|
|
|
break;
|
2001-09-20 13:52:49 +00:00
|
|
|
case DYN_KEEP_STATE: /* bidir, no mask */
|
2002-05-12 20:52:21 +00:00
|
|
|
printf(" <->");
|
|
|
|
break;
|
2001-09-20 13:52:49 +00:00
|
|
|
}
|
2001-06-04 23:56:26 +00:00
|
|
|
|
|
|
|
if (do_resolv && (pe = getprotobynumber(d->id.proto)) != NULL)
|
|
|
|
printf(" %s,", pe->p_name);
|
|
|
|
else
|
|
|
|
printf(" %u,", d->id.proto);
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
a.s_addr = htonl(d->id.src_ip);
|
2001-11-01 08:45:02 +00:00
|
|
|
printf(" %s %d", inet_ntoa(a), d->id.src_port);
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
a.s_addr = htonl(d->id.dst_ip);
|
2001-09-27 23:44:27 +00:00
|
|
|
printf("<-> %s %d", inet_ntoa(a), d->id.dst_port);
|
2001-06-04 23:56:26 +00:00
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
2000-02-10 14:25:26 +00:00
|
|
|
int
|
|
|
|
sort_q(const void *pa, const void *pb)
|
|
|
|
{
|
2001-06-04 23:56:26 +00:00
|
|
|
int rev = (do_sort < 0);
|
|
|
|
int field = rev ? -do_sort : do_sort;
|
|
|
|
long long res = 0;
|
|
|
|
const struct dn_flow_queue *a = pa;
|
|
|
|
const struct dn_flow_queue *b = pb;
|
|
|
|
|
|
|
|
switch (field) {
|
|
|
|
case 1: /* pkts */
|
|
|
|
res = a->len - b->len;
|
|
|
|
break;
|
|
|
|
case 2: /* bytes */
|
|
|
|
res = a->len_bytes - b->len_bytes;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3: /* tot pkts */
|
|
|
|
res = a->tot_pkts - b->tot_pkts;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: /* tot bytes */
|
|
|
|
res = a->tot_bytes - b->tot_bytes;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (res < 0)
|
|
|
|
res = -1;
|
|
|
|
if (res > 0)
|
|
|
|
res = 1;
|
|
|
|
return (int)(rev ? res : -res);
|
2000-02-10 14:25:26 +00:00
|
|
|
}
|
|
|
|
|
2000-06-08 10:08:39 +00:00
|
|
|
static void
|
|
|
|
list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
|
|
|
|
{
|
2001-06-04 23:56:26 +00:00
|
|
|
int l;
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
|
|
|
|
fs->flow_mask.proto,
|
|
|
|
fs->flow_mask.src_ip, fs->flow_mask.src_port,
|
|
|
|
fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
|
|
|
|
if (fs->rq_elements == 0)
|
|
|
|
return;
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
printf("BKT Prot ___Source IP/port____ "
|
|
|
|
"____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
|
|
|
|
if (do_sort != 0)
|
|
|
|
heapsort(q, fs->rq_elements, sizeof *q, sort_q);
|
|
|
|
for (l = 0; l < fs->rq_elements; l++) {
|
|
|
|
struct in_addr ina;
|
|
|
|
struct protoent *pe;
|
|
|
|
|
|
|
|
ina.s_addr = htonl(q[l].id.src_ip);
|
|
|
|
printf("%3d ", q[l].hash_slot);
|
|
|
|
pe = getprotobynumber(q[l].id.proto);
|
|
|
|
if (pe)
|
|
|
|
printf("%-4s ", pe->p_name);
|
|
|
|
else
|
|
|
|
printf("%4u ", q[l].id.proto);
|
|
|
|
printf("%15s/%-5d ",
|
|
|
|
inet_ntoa(ina), q[l].id.src_port);
|
|
|
|
ina.s_addr = htonl(q[l].id.dst_ip);
|
|
|
|
printf("%15s/%-5d ",
|
|
|
|
inet_ntoa(ina), q[l].id.dst_port);
|
|
|
|
printf("%4qu %8qu %2u %4u %3u\n",
|
|
|
|
q[l].tot_pkts, q[l].tot_bytes,
|
|
|
|
q[l].len, q[l].len_bytes, q[l].drops);
|
|
|
|
if (verbose)
|
|
|
|
printf(" S %20qd F %20qd\n",
|
|
|
|
q[l].S, q[l].F);
|
|
|
|
}
|
2000-06-08 10:08:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_flowset_parms(struct dn_flow_set *fs, char *prefix)
|
|
|
|
{
|
2001-06-04 23:56:26 +00:00
|
|
|
int l;
|
|
|
|
char qs[30];
|
|
|
|
char plr[30];
|
2001-10-29 00:37:24 +00:00
|
|
|
char red[90]; /* Display RED parameters */
|
2001-06-04 23:56:26 +00:00
|
|
|
|
|
|
|
l = fs->qsize;
|
|
|
|
if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
|
|
|
|
if (l >= 8192)
|
|
|
|
sprintf(qs, "%d KB", l / 1024);
|
|
|
|
else
|
|
|
|
sprintf(qs, "%d B", l);
|
|
|
|
} else
|
|
|
|
sprintf(qs, "%3d sl.", l);
|
|
|
|
if (fs->plr)
|
|
|
|
sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
|
|
|
|
else
|
|
|
|
plr[0] = '\0';
|
2001-10-29 03:25:49 +00:00
|
|
|
if (fs->flags_fs & DN_IS_RED) /* RED parameters */
|
2001-06-04 23:56:26 +00:00
|
|
|
sprintf(red,
|
2001-10-29 03:25:49 +00:00
|
|
|
"\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
|
2001-06-04 23:56:26 +00:00
|
|
|
(fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
|
2001-10-29 03:25:49 +00:00
|
|
|
1.0 * fs->w_q / (double)(1 << SCALE_RED),
|
2001-06-04 23:56:26 +00:00
|
|
|
SCALE_VAL(fs->min_th),
|
|
|
|
SCALE_VAL(fs->max_th),
|
2001-10-29 03:25:49 +00:00
|
|
|
1.0 * fs->max_p / (double)(1 << SCALE_RED));
|
2000-06-08 10:08:39 +00:00
|
|
|
else
|
2001-06-04 23:56:26 +00:00
|
|
|
sprintf(red, "droptail");
|
|
|
|
|
|
|
|
printf("%s %s%s %d queues (%d buckets) %s\n",
|
|
|
|
prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
|
2000-06-08 10:08:39 +00:00
|
|
|
}
|
|
|
|
|
1998-09-28 22:56:37 +00:00
|
|
|
static void
|
2001-06-04 23:56:26 +00:00
|
|
|
list(int ac, char *av[])
|
1994-10-28 15:06:53 +00:00
|
|
|
{
|
2001-06-04 23:56:26 +00:00
|
|
|
struct ip_fw *rules, *r;
|
|
|
|
struct ipfw_dyn_rule *dynrules, *d;
|
1999-01-22 01:46:32 +00:00
|
|
|
struct dn_pipe *pipes;
|
|
|
|
void *data = NULL;
|
2001-06-04 23:56:26 +00:00
|
|
|
int n, nbytes, nstat, ndyn;
|
|
|
|
int exitval = EX_OK;
|
|
|
|
int lac;
|
|
|
|
char **lav;
|
|
|
|
u_long rnum;
|
|
|
|
char *endptr;
|
|
|
|
int seen = 0;
|
1996-02-24 13:39:46 +00:00
|
|
|
|
1999-01-22 01:46:32 +00:00
|
|
|
/* get rules or pipes from kernel, resizing array as necessary */
|
|
|
|
{
|
|
|
|
const int unit = do_pipe ? sizeof(*pipes) : sizeof(*rules);
|
|
|
|
const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET;
|
2000-06-14 10:07:22 +00:00
|
|
|
int nalloc = unit;
|
2001-06-04 23:56:26 +00:00
|
|
|
nbytes = nalloc;
|
1999-01-22 01:46:32 +00:00
|
|
|
|
2000-06-14 10:07:22 +00:00
|
|
|
while (nbytes >= nalloc) {
|
1999-01-22 01:46:32 +00:00
|
|
|
nalloc = nalloc * 2 + 200;
|
2001-06-04 23:56:26 +00:00
|
|
|
nbytes = nalloc;
|
1999-01-22 01:46:32 +00:00
|
|
|
if ((data = realloc(data, nbytes)) == NULL)
|
|
|
|
err(EX_OSERR, "realloc");
|
|
|
|
if (getsockopt(s, IPPROTO_IP, ocmd, data, &nbytes) < 0)
|
|
|
|
err(EX_OSERR, "getsockopt(IP_%s_GET)",
|
|
|
|
do_pipe ? "DUMMYNET" : "FW");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* display requested pipes */
|
|
|
|
if (do_pipe) {
|
2001-06-04 23:56:26 +00:00
|
|
|
u_long rulenum;
|
|
|
|
void *next = data;
|
|
|
|
struct dn_pipe *p = (struct dn_pipe *) data;
|
|
|
|
struct dn_flow_set *fs;
|
|
|
|
struct dn_flow_queue *q;
|
|
|
|
int l;
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (ac > 0)
|
|
|
|
rulenum = strtoul(*av++, NULL, 10);
|
1999-01-22 01:46:32 +00:00
|
|
|
else
|
2001-06-04 23:56:26 +00:00
|
|
|
rulenum = 0;
|
|
|
|
for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) {
|
|
|
|
double b = p->bandwidth;
|
|
|
|
char buf[30];
|
|
|
|
char prefix[80];
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (p->next != (struct dn_pipe *)DN_IS_PIPE)
|
|
|
|
break;
|
|
|
|
l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
|
2001-10-29 00:37:24 +00:00
|
|
|
next = (void *)p + l;
|
2001-06-04 23:56:26 +00:00
|
|
|
nbytes -= l;
|
|
|
|
q = (struct dn_flow_queue *)(p+1);
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (rulenum != 0 && rulenum != p->pipe_nr)
|
|
|
|
continue;
|
|
|
|
if (p->if_name[0] != '\0')
|
|
|
|
sprintf(buf, "%s", p->if_name);
|
|
|
|
else if (b == 0)
|
|
|
|
sprintf(buf, "unlimited");
|
|
|
|
else if (b >= 1000000)
|
|
|
|
sprintf(buf, "%7.3f Mbit/s", b/1000000);
|
|
|
|
else if (b >= 1000)
|
|
|
|
sprintf(buf, "%7.3f Kbit/s", b/1000);
|
|
|
|
else
|
|
|
|
sprintf(buf, "%7.3f bit/s ", b);
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
sprintf(prefix, "%05d: %s %4d ms ",
|
|
|
|
p->pipe_nr, buf, p->delay);
|
|
|
|
print_flowset_parms(&(p->fs), prefix);
|
|
|
|
if (verbose)
|
|
|
|
printf(" V %20qd\n", p->V >> MY_M);
|
|
|
|
list_queues(&(p->fs), q);
|
|
|
|
}
|
|
|
|
fs = (struct dn_flow_set *) next;
|
|
|
|
for (; nbytes >= sizeof *fs; fs = (struct dn_flow_set *)next) {
|
|
|
|
char prefix[80];
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (fs->next != (struct dn_flow_set *)DN_IS_QUEUE)
|
|
|
|
break;
|
|
|
|
l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
|
2001-10-29 00:37:24 +00:00
|
|
|
next = (void *)fs + l;
|
2001-06-04 23:56:26 +00:00
|
|
|
nbytes -= l;
|
|
|
|
q = (struct dn_flow_queue *)(fs+1);
|
|
|
|
sprintf(prefix, "q%05d: weight %d pipe %d ",
|
|
|
|
fs->fs_nr, fs->weight, fs->parent_nr);
|
|
|
|
print_flowset_parms(fs, prefix);
|
|
|
|
list_queues(fs, q);
|
2001-10-29 00:37:24 +00:00
|
|
|
}
|
|
|
|
free(data);
|
|
|
|
return;
|
1999-01-22 01:46:32 +00:00
|
|
|
}
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
rules = (struct ip_fw *)data;
|
|
|
|
for (nstat = 0; rules[nstat].fw_number < 65535; ++nstat)
|
|
|
|
/* nothing */ ;
|
|
|
|
nstat++; /* counting starts from 0 ... */
|
|
|
|
dynrules = (struct ipfw_dyn_rule *)&rules[nstat];
|
|
|
|
ndyn = (nbytes - (nstat * sizeof *rules)) / sizeof *dynrules;
|
|
|
|
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
/* if no rule numbers were specified, list all rules */
|
1999-01-22 01:46:32 +00:00
|
|
|
if (ac == 0) {
|
2001-06-04 23:56:26 +00:00
|
|
|
for (n = 0; n < nstat; n++)
|
|
|
|
show_ipfw(&rules[n]);
|
1999-01-22 01:46:32 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (do_dynamic && ndyn) {
|
|
|
|
printf("## Dynamic rules:\n");
|
|
|
|
for (n = 0, d = dynrules; n < ndyn; n++, d++)
|
|
|
|
show_dyn_ipfw(d);
|
1999-01-22 01:46:32 +00:00
|
|
|
}
|
2001-06-04 23:56:26 +00:00
|
|
|
free(data);
|
|
|
|
return;
|
|
|
|
}
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
/* display specific rules requested on command line */
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
for (lac = ac, lav = av; lac != 0; lac--) {
|
|
|
|
/* convert command line rule # */
|
|
|
|
rnum = strtoul(*lav++, &endptr, 10);
|
|
|
|
if (*endptr) {
|
|
|
|
exitval = EX_USAGE;
|
|
|
|
warnx("invalid rule number: %s", *(lav - 1));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (n = seen = 0, r = rules; n < nstat; n++, r++) {
|
|
|
|
if (r->fw_number > rnum)
|
|
|
|
break;
|
|
|
|
if (r->fw_number == rnum) {
|
|
|
|
show_ipfw(r);
|
|
|
|
seen = 1;
|
1998-01-07 02:23:04 +00:00
|
|
|
}
|
2001-06-04 23:56:26 +00:00
|
|
|
}
|
|
|
|
if (!seen) {
|
|
|
|
/* give precedence to other error(s) */
|
|
|
|
if (exitval == EX_OK)
|
|
|
|
exitval = EX_UNAVAILABLE;
|
|
|
|
warnx("rule %lu does not exist", rnum);
|
|
|
|
}
|
|
|
|
}
|
1999-01-22 01:46:32 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
printf("## Dynamic rules:\n");
|
|
|
|
if (do_dynamic && ndyn) {
|
|
|
|
for (lac = ac, lav = av; lac != 0; lac--) {
|
|
|
|
rnum = strtoul(*lav++, &endptr, 10);
|
|
|
|
if (*endptr)
|
|
|
|
/* already warned */
|
|
|
|
continue;
|
|
|
|
for (n = 0, d = dynrules; n < ndyn; n++, d++) {
|
2001-09-27 23:44:27 +00:00
|
|
|
if ((int)(d->rule) > rnum)
|
1999-01-22 01:46:32 +00:00
|
|
|
break;
|
2001-09-27 23:44:27 +00:00
|
|
|
if ((int)(d->rule) == rnum)
|
2001-06-04 23:56:26 +00:00
|
|
|
show_dyn_ipfw(d);
|
1998-01-07 02:23:04 +00:00
|
|
|
}
|
|
|
|
}
|
2001-06-04 23:56:26 +00:00
|
|
|
}
|
2000-02-10 14:25:26 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
ac = 0;
|
2001-10-29 00:37:24 +00:00
|
|
|
|
1999-01-22 01:46:32 +00:00
|
|
|
free(data);
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (exitval != EX_OK)
|
|
|
|
exit(exitval);
|
1994-10-28 15:06:53 +00:00
|
|
|
}
|
|
|
|
|
1997-06-02 05:02:37 +00:00
|
|
|
static void
|
2001-07-22 06:40:11 +00:00
|
|
|
show_usage(void)
|
1994-11-16 10:18:18 +00:00
|
|
|
{
|
1997-06-13 06:27:12 +00:00
|
|
|
fprintf(stderr, "usage: ipfw [options]\n"
|
1997-06-02 05:02:37 +00:00
|
|
|
" add [number] rule\n"
|
1999-06-02 05:59:48 +00:00
|
|
|
" pipe number config [pipeconfig]\n"
|
2002-05-12 20:52:21 +00:00
|
|
|
" queue number config [queueconfig]\n"
|
|
|
|
" [pipe] flush\n"
|
|
|
|
" [pipe] delete number ...\n"
|
|
|
|
" [pipe] {list|show} [number ...]\n"
|
|
|
|
" {zero|resetlog} [number ...]\n"
|
|
|
|
" rule: [prob <match_probability>] action (mac-hdr|ip-hdr) options...\n"
|
|
|
|
" action:\n"
|
1997-06-02 05:02:37 +00:00
|
|
|
" {allow|permit|accept|pass|deny|drop|reject|unreach code|\n"
|
2001-06-04 23:56:26 +00:00
|
|
|
" reset|count|skipto num|divert port|tee port|fwd ip|\n"
|
|
|
|
" pipe num} [log [logamount count]]\n"
|
2001-10-28 02:10:40 +00:00
|
|
|
" proto: {ip|tcp|udp|icmp|<number>}\n"
|
2001-06-04 23:56:26 +00:00
|
|
|
" src: from [not] {me|any|ip[{/bits|:mask}]} [{port[-port]}, [port], ...]\n"
|
|
|
|
" dst: to [not] {me|any|ip[{/bits|:mask}]} [{port[-port]}, [port], ...]\n"
|
1997-06-02 05:02:37 +00:00
|
|
|
" extras:\n"
|
1999-06-19 18:43:33 +00:00
|
|
|
" uid {user id}\n"
|
|
|
|
" gid {group id}\n"
|
2001-06-04 23:56:26 +00:00
|
|
|
" fragment (may not be used with ports or tcpflags)\n"
|
1997-06-02 05:02:37 +00:00
|
|
|
" in\n"
|
|
|
|
" out\n"
|
|
|
|
" {xmit|recv|via} {iface|ip|any}\n"
|
|
|
|
" {established|setup}\n"
|
2001-06-04 23:56:26 +00:00
|
|
|
" tcpflags [!]{syn|fin|rst|ack|psh|urg}, ...\n"
|
|
|
|
" ipoptions [!]{ssrr|lsrr|rr|ts}, ...\n"
|
2000-10-02 03:03:31 +00:00
|
|
|
" iplen {length}\n"
|
2000-10-03 11:23:29 +00:00
|
|
|
" ipid {identification number}\n"
|
2001-12-21 18:43:37 +00:00
|
|
|
" ipprecedence {precedence}\n"
|
2001-06-04 23:56:26 +00:00
|
|
|
" iptos [!]{lowdelay|throughput|reliability|mincost|congestion}, ...\n"
|
2000-10-02 03:03:31 +00:00
|
|
|
" ipttl {time to live}\n"
|
|
|
|
" ipversion {version number}\n"
|
2001-06-04 23:56:26 +00:00
|
|
|
" tcpoptions [!]{mss|window|sack|ts|cc}, ...\n"
|
2000-10-02 03:03:31 +00:00
|
|
|
" tcpseq {sequence number}\n"
|
|
|
|
" tcpack {acknowledgement number}\n"
|
|
|
|
" tcpwin {window size}\n"
|
2001-06-04 23:56:26 +00:00
|
|
|
" icmptypes {type[, type]}...\n"
|
2001-07-22 06:40:11 +00:00
|
|
|
" keep-state [method]\n"
|
1999-06-02 05:59:48 +00:00
|
|
|
" pipeconfig:\n"
|
1999-05-24 10:01:22 +00:00
|
|
|
" {bw|bandwidth} <number>{bit/s|Kbit/s|Mbit/s|Bytes/s|KBytes/s|MBytes/s}\n"
|
2000-06-08 10:08:39 +00:00
|
|
|
" {bw|bandwidth} interface_name\n"
|
1999-05-24 10:01:22 +00:00
|
|
|
" delay <milliseconds>\n"
|
|
|
|
" queue <size>{packets|Bytes|KBytes}\n"
|
|
|
|
" plr <fraction>\n"
|
2000-01-08 11:19:19 +00:00
|
|
|
" mask {all| [dst-ip|src-ip|dst-port|src-port|proto] <number>}\n"
|
|
|
|
" buckets <number>}\n"
|
2000-06-08 10:08:39 +00:00
|
|
|
" {red|gred} <fraction>/<number>/<number>/<fraction>\n"
|
|
|
|
" droptail\n"
|
1999-05-24 10:01:22 +00:00
|
|
|
);
|
1997-06-02 05:02:37 +00:00
|
|
|
|
1998-01-07 02:23:04 +00:00
|
|
|
exit(EX_USAGE);
|
1994-11-16 10:18:18 +00:00
|
|
|
}
|
1994-10-28 15:06:53 +00:00
|
|
|
|
1997-06-02 05:02:37 +00:00
|
|
|
static int
|
2001-06-04 23:56:26 +00:00
|
|
|
lookup_host (char *host, struct in_addr *ipaddr)
|
1996-06-09 23:46:22 +00:00
|
|
|
{
|
1999-06-04 11:20:59 +00:00
|
|
|
struct hostent *he;
|
1996-06-09 23:46:22 +00:00
|
|
|
|
1999-06-04 11:20:59 +00:00
|
|
|
if (!inet_aton(host, ipaddr)) {
|
|
|
|
if ((he = gethostbyname(host)) == NULL)
|
|
|
|
return(-1);
|
|
|
|
*ipaddr = *(struct in_addr *)he->h_addr_list[0];
|
|
|
|
}
|
1996-06-09 23:46:22 +00:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
1998-09-28 22:56:37 +00:00
|
|
|
static void
|
2001-06-04 23:56:26 +00:00
|
|
|
fill_ip(struct in_addr *ipno, struct in_addr *mask, int *acp, char ***avp)
|
1994-11-16 10:18:18 +00:00
|
|
|
{
|
1996-02-24 00:20:56 +00:00
|
|
|
int ac = *acp;
|
|
|
|
char **av = *avp;
|
|
|
|
char *p = 0, md = 0;
|
1994-10-28 15:06:53 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (ac && !strncmp(*av, "any", strlen(*av))) {
|
1996-02-24 00:20:56 +00:00
|
|
|
ipno->s_addr = mask->s_addr = 0; av++; ac--;
|
|
|
|
} else {
|
2002-05-12 20:52:21 +00:00
|
|
|
u_int32_t i;
|
|
|
|
|
1996-02-24 00:20:56 +00:00
|
|
|
p = strchr(*av, '/');
|
2001-06-04 23:56:26 +00:00
|
|
|
if (!p)
|
1996-02-24 00:20:56 +00:00
|
|
|
p = strchr(*av, ':');
|
|
|
|
if (p) {
|
|
|
|
md = *p;
|
2001-06-04 23:56:26 +00:00
|
|
|
*p++ = '\0';
|
1996-02-24 00:20:56 +00:00
|
|
|
}
|
|
|
|
|
1997-06-02 05:02:37 +00:00
|
|
|
if (lookup_host(*av, ipno) != 0)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
|
1996-06-23 20:47:51 +00:00
|
|
|
switch (md) {
|
2002-05-12 20:52:21 +00:00
|
|
|
case ':':
|
|
|
|
if (!inet_aton(p, mask))
|
|
|
|
errx(EX_DATAERR, "bad netmask ``%s''", p);
|
|
|
|
break;
|
|
|
|
case '/':
|
|
|
|
i = atoi(p);
|
|
|
|
if (i == 0)
|
|
|
|
mask->s_addr = 0;
|
|
|
|
else if (i > 32)
|
|
|
|
errx(EX_DATAERR, "bad width ``%s''", p);
|
|
|
|
else
|
|
|
|
mask->s_addr = htonl(~0 << (32 - i));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
mask->s_addr = htonl(~0);
|
|
|
|
break;
|
1996-06-23 20:47:51 +00:00
|
|
|
}
|
|
|
|
ipno->s_addr &= mask->s_addr;
|
1996-02-24 00:20:56 +00:00
|
|
|
av++;
|
|
|
|
ac--;
|
|
|
|
}
|
|
|
|
*acp = ac;
|
|
|
|
*avp = av;
|
1994-11-16 10:18:18 +00:00
|
|
|
}
|
1994-10-28 15:06:53 +00:00
|
|
|
|
1997-06-02 05:02:37 +00:00
|
|
|
static void
|
|
|
|
fill_reject_code(u_short *codep, char *str)
|
|
|
|
{
|
|
|
|
struct icmpcode *ic;
|
|
|
|
u_long val;
|
|
|
|
char *s;
|
|
|
|
|
2002-09-25 11:22:36 +00:00
|
|
|
if (str == '\0')
|
|
|
|
errx(EX_DATAERR, "missing unreachable code");
|
1997-06-02 05:02:37 +00:00
|
|
|
val = strtoul(str, &s, 0);
|
|
|
|
if (s != str && *s == '\0' && val < 0x100) {
|
|
|
|
*codep = val;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (ic = icmpcodes; ic->str; ic++)
|
|
|
|
if (!strcasecmp(str, ic->str)) {
|
|
|
|
*codep = ic->code;
|
|
|
|
return;
|
|
|
|
}
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str);
|
1997-06-02 05:02:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2001-06-04 23:56:26 +00:00
|
|
|
add_port(u_short *cnt, u_short *ptr, u_short off, u_short port)
|
1996-05-11 20:31:55 +00:00
|
|
|
{
|
|
|
|
if (off + *cnt >= IP_FW_MAX_PORTS)
|
1998-01-07 02:23:04 +00:00
|
|
|
errx(EX_USAGE, "too many ports (max is %d)", IP_FW_MAX_PORTS);
|
1996-05-11 20:31:55 +00:00
|
|
|
ptr[off+*cnt] = port;
|
|
|
|
(*cnt)++;
|
|
|
|
}
|
|
|
|
|
1997-06-23 22:32:13 +00:00
|
|
|
static int
|
2000-10-04 07:59:19 +00:00
|
|
|
lookup_port(const char *arg, int proto, int test, int nodash)
|
1997-06-23 22:32:13 +00:00
|
|
|
{
|
|
|
|
int val;
|
|
|
|
char *earg, buf[32];
|
|
|
|
struct servent *s;
|
1999-06-11 09:43:53 +00:00
|
|
|
char *p, *q;
|
1997-06-23 22:32:13 +00:00
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "%s", arg);
|
1999-06-11 09:43:53 +00:00
|
|
|
|
|
|
|
for (p = q = buf; *p; *q++ = *p++) {
|
|
|
|
if (*p == '\\') {
|
|
|
|
if (*(p+1))
|
|
|
|
p++;
|
|
|
|
} else {
|
|
|
|
if (*p == ',' || (nodash && *p == '-'))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*q = '\0';
|
|
|
|
|
1997-06-23 22:32:13 +00:00
|
|
|
val = (int) strtoul(buf, &earg, 0);
|
|
|
|
if (!*buf || *earg) {
|
2000-10-04 07:59:19 +00:00
|
|
|
char *protocol = NULL;
|
|
|
|
|
|
|
|
if (proto != 0) {
|
|
|
|
struct protoent *pe = getprotobynumber(proto);
|
|
|
|
|
|
|
|
if (pe)
|
|
|
|
protocol = pe->p_name;
|
|
|
|
}
|
|
|
|
|
1997-06-23 22:32:13 +00:00
|
|
|
setservent(1);
|
2002-05-12 20:52:21 +00:00
|
|
|
s = getservbyname(buf, protocol);
|
|
|
|
if (s != NULL)
|
1997-06-23 22:32:13 +00:00
|
|
|
val = htons(s->s_port);
|
2002-05-12 20:52:21 +00:00
|
|
|
else {
|
2001-06-04 23:56:26 +00:00
|
|
|
if (!test)
|
1999-06-11 09:43:53 +00:00
|
|
|
errx(EX_DATAERR, "unknown port ``%s''", buf);
|
1997-06-23 22:32:13 +00:00
|
|
|
val = -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (val < 0 || val > 0xffff) {
|
2001-06-04 23:56:26 +00:00
|
|
|
if (!test)
|
|
|
|
errx(EX_DATAERR,
|
|
|
|
"port ``%s'' out of range", buf);
|
1997-06-23 22:32:13 +00:00
|
|
|
val = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return(val);
|
|
|
|
}
|
|
|
|
|
2000-01-08 11:19:19 +00:00
|
|
|
/*
|
|
|
|
* return: 0 normally, 1 if first pair is a range,
|
|
|
|
* 2 if first pair is a port+mask
|
|
|
|
*/
|
1998-09-28 22:56:37 +00:00
|
|
|
static int
|
2000-10-04 07:59:19 +00:00
|
|
|
fill_port(u_short *cnt, u_short *ptr, u_short off, char *arg, int proto)
|
1994-11-16 10:18:18 +00:00
|
|
|
{
|
1996-06-09 23:46:22 +00:00
|
|
|
char *s;
|
1996-05-11 20:31:55 +00:00
|
|
|
int initial_range = 0;
|
1996-02-24 00:20:56 +00:00
|
|
|
|
2000-01-08 11:19:19 +00:00
|
|
|
for (s = arg; *s && *s != ',' && *s != '-' && *s != ':'; s++) {
|
1999-06-11 09:43:53 +00:00
|
|
|
if (*s == '\\' && *(s+1))
|
|
|
|
s++;
|
|
|
|
}
|
2000-01-08 11:19:19 +00:00
|
|
|
if (*s == ':') {
|
|
|
|
*s++ = '\0';
|
|
|
|
if (strchr(arg, ','))
|
|
|
|
errx(EX_USAGE, "port/mask must be first in list");
|
2001-06-04 23:56:26 +00:00
|
|
|
add_port(cnt, ptr, off,
|
|
|
|
*arg ? lookup_port(arg, proto, 0, 0) : 0x0000);
|
2000-01-08 11:19:19 +00:00
|
|
|
arg = s;
|
2001-06-04 23:56:26 +00:00
|
|
|
s = strchr(arg, ',');
|
2000-01-08 11:19:19 +00:00
|
|
|
if (s)
|
|
|
|
*s++ = '\0';
|
2001-06-04 23:56:26 +00:00
|
|
|
add_port(cnt, ptr, off,
|
|
|
|
*arg ? lookup_port(arg, proto, 0, 0) : 0xffff);
|
2000-01-08 11:19:19 +00:00
|
|
|
arg = s;
|
|
|
|
initial_range = 2;
|
2002-05-12 20:52:21 +00:00
|
|
|
} else if (*s == '-') {
|
1996-02-24 00:20:56 +00:00
|
|
|
*s++ = '\0';
|
1996-05-11 20:31:55 +00:00
|
|
|
if (strchr(arg, ','))
|
1998-01-07 02:23:04 +00:00
|
|
|
errx(EX_USAGE, "port range must be first in list");
|
2001-06-04 23:56:26 +00:00
|
|
|
add_port(cnt, ptr, off,
|
|
|
|
*arg ? lookup_port(arg, proto, 0, 0) : 0x0000);
|
1996-05-11 20:31:55 +00:00
|
|
|
arg = s;
|
2001-06-04 23:56:26 +00:00
|
|
|
s = strchr(arg, ',');
|
1996-05-11 20:31:55 +00:00
|
|
|
if (s)
|
1996-02-24 00:20:56 +00:00
|
|
|
*s++ = '\0';
|
2001-06-04 23:56:26 +00:00
|
|
|
add_port(cnt, ptr, off,
|
|
|
|
*arg ? lookup_port(arg, proto, 0, 0) : 0xffff);
|
1996-05-11 20:31:55 +00:00
|
|
|
arg = s;
|
|
|
|
initial_range = 1;
|
1996-02-24 00:20:56 +00:00
|
|
|
}
|
1996-05-11 20:31:55 +00:00
|
|
|
while (arg != NULL) {
|
2001-06-04 23:56:26 +00:00
|
|
|
s = strchr(arg, ',');
|
1996-05-11 20:31:55 +00:00
|
|
|
if (s)
|
1996-02-24 00:20:56 +00:00
|
|
|
*s++ = '\0';
|
2000-10-04 07:59:19 +00:00
|
|
|
add_port(cnt, ptr, off, lookup_port(arg, proto, 0, 0));
|
1996-05-11 20:31:55 +00:00
|
|
|
arg = s;
|
1994-11-16 10:18:18 +00:00
|
|
|
}
|
1996-05-11 20:31:55 +00:00
|
|
|
return initial_range;
|
1994-11-16 10:18:18 +00:00
|
|
|
}
|
1994-10-28 15:06:53 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/*
|
|
|
|
* helper function to process a set of flags and set bits in the
|
|
|
|
* appropriate masks.
|
|
|
|
*/
|
1998-09-28 22:56:37 +00:00
|
|
|
static void
|
2002-05-12 20:52:21 +00:00
|
|
|
fill_flags(u_char *set, u_char *reset, struct _flaglist *flags, char **vp)
|
1994-11-16 10:18:18 +00:00
|
|
|
{
|
2002-05-12 20:52:21 +00:00
|
|
|
char *p = *vp, *q; /* parameter */
|
|
|
|
u_char *d; /* which mask we are working on */
|
1995-05-30 06:12:45 +00:00
|
|
|
|
1996-02-24 00:20:56 +00:00
|
|
|
while (p && *p) {
|
1996-06-09 23:46:22 +00:00
|
|
|
int i;
|
|
|
|
|
1996-02-24 00:20:56 +00:00
|
|
|
if (*p == '!') {
|
|
|
|
p++;
|
|
|
|
d = reset;
|
2002-05-12 20:52:21 +00:00
|
|
|
} else
|
1996-02-24 00:20:56 +00:00
|
|
|
d = set;
|
|
|
|
q = strchr(p, ',');
|
2001-06-04 23:56:26 +00:00
|
|
|
if (q)
|
1996-02-24 00:20:56 +00:00
|
|
|
*q++ = '\0';
|
2002-05-12 20:52:21 +00:00
|
|
|
for (i = 0; flags[i].value != 0; ++i)
|
1996-06-09 23:46:22 +00:00
|
|
|
if (!strncmp(p, flags[i].name, strlen(p))) {
|
|
|
|
*d |= flags[i].value;
|
|
|
|
break;
|
|
|
|
}
|
2002-05-12 20:52:21 +00:00
|
|
|
if (flags[i].value == 0)
|
|
|
|
errx(EX_DATAERR, "invalid %s ``%s''", flags[i].name, p);
|
2000-10-02 03:03:31 +00:00
|
|
|
p = q;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-09-28 22:56:37 +00:00
|
|
|
static void
|
2001-06-04 23:56:26 +00:00
|
|
|
fill_icmptypes(unsigned *types, char **vp, u_int *fw_flg)
|
1996-06-09 23:46:22 +00:00
|
|
|
{
|
2001-06-04 23:56:26 +00:00
|
|
|
unsigned long icmptype;
|
1996-06-09 23:46:22 +00:00
|
|
|
char *c = *vp;
|
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
while (*c) {
|
|
|
|
if (*c == ',')
|
1996-06-09 23:46:22 +00:00
|
|
|
++c;
|
|
|
|
|
|
|
|
icmptype = strtoul(c, &c, 0);
|
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (*c != ',' && *c != '\0')
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "invalid ICMP type");
|
1996-06-09 23:46:22 +00:00
|
|
|
|
1997-08-08 14:36:29 +00:00
|
|
|
if (icmptype >= IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "ICMP type out of range");
|
1996-06-09 23:46:22 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
types[icmptype / (sizeof(unsigned) * 8)] |=
|
1996-06-09 23:46:22 +00:00
|
|
|
1 << (icmptype % (sizeof(unsigned) * 8));
|
|
|
|
*fw_flg |= IP_FW_F_ICMPBIT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-09-28 22:56:37 +00:00
|
|
|
static void
|
2001-06-04 23:56:26 +00:00
|
|
|
delete(int ac, char *av[])
|
1995-10-23 03:58:06 +00:00
|
|
|
{
|
1996-02-24 00:20:56 +00:00
|
|
|
struct ip_fw rule;
|
1998-12-14 18:43:03 +00:00
|
|
|
struct dn_pipe pipe;
|
1996-02-24 00:20:56 +00:00
|
|
|
int i;
|
1998-01-07 02:23:04 +00:00
|
|
|
int exitval = EX_OK;
|
|
|
|
|
1996-02-24 00:20:56 +00:00
|
|
|
memset(&rule, 0, sizeof rule);
|
1998-12-14 18:43:03 +00:00
|
|
|
memset(&pipe, 0, sizeof pipe);
|
1995-10-23 03:58:06 +00:00
|
|
|
|
1996-02-24 00:20:56 +00:00
|
|
|
av++; ac--;
|
1995-10-23 03:58:06 +00:00
|
|
|
|
1996-02-24 00:20:56 +00:00
|
|
|
/* Rule number */
|
1997-06-02 05:02:37 +00:00
|
|
|
while (ac && isdigit(**av)) {
|
2001-10-29 00:37:24 +00:00
|
|
|
i = atoi(*av); av++; ac--;
|
|
|
|
if (do_pipe) {
|
|
|
|
if (do_pipe == 1)
|
|
|
|
pipe.pipe_nr = i;
|
|
|
|
else
|
|
|
|
pipe.fs.fs_nr = i;
|
2001-10-29 03:25:49 +00:00
|
|
|
i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_DEL,
|
|
|
|
&pipe, sizeof pipe);
|
2001-10-29 00:37:24 +00:00
|
|
|
if (i) {
|
|
|
|
exitval = 1;
|
2001-10-29 03:25:49 +00:00
|
|
|
warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
|
|
|
|
do_pipe == 1 ? pipe.pipe_nr :
|
|
|
|
pipe.fs.fs_nr);
|
2001-10-29 00:37:24 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rule.fw_number = i;
|
|
|
|
i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, &rule,
|
|
|
|
sizeof rule);
|
|
|
|
if (i) {
|
|
|
|
exitval = EX_UNAVAILABLE;
|
|
|
|
warn("rule %u: setsockopt(IP_FW_DEL)",
|
|
|
|
rule.fw_number);
|
|
|
|
}
|
1998-01-06 00:11:57 +00:00
|
|
|
}
|
1995-10-01 21:54:05 +00:00
|
|
|
}
|
1998-01-07 02:23:04 +00:00
|
|
|
if (exitval != EX_OK)
|
|
|
|
exit(exitval);
|
1996-02-24 00:20:56 +00:00
|
|
|
}
|
1995-02-24 14:32:45 +00:00
|
|
|
|
1997-06-02 05:02:37 +00:00
|
|
|
static void
|
|
|
|
verify_interface(union ip_fw_if *ifu)
|
1996-10-17 01:05:03 +00:00
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If a unit was specified, check for that exact interface.
|
|
|
|
* If a wildcard was specified, check for unit 0.
|
|
|
|
*/
|
2001-06-04 23:56:26 +00:00
|
|
|
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
|
1997-06-02 05:02:37 +00:00
|
|
|
ifu->fu_via_if.name,
|
|
|
|
ifu->fu_via_if.unit == -1 ? 0 : ifu->fu_via_if.unit);
|
1996-10-17 01:05:03 +00:00
|
|
|
|
|
|
|
if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
|
2001-06-04 23:56:26 +00:00
|
|
|
warnx("warning: interface ``%s'' does not exist",
|
|
|
|
ifr.ifr_name);
|
1997-06-02 05:02:37 +00:00
|
|
|
}
|
1996-10-17 01:05:03 +00:00
|
|
|
|
1997-06-02 05:02:37 +00:00
|
|
|
static void
|
|
|
|
fill_iface(char *which, union ip_fw_if *ifu, int *byname, int ac, char *arg)
|
|
|
|
{
|
|
|
|
if (!ac)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_USAGE, "missing argument for ``%s''", which);
|
1997-06-02 05:02:37 +00:00
|
|
|
|
|
|
|
/* Parse the interface or address */
|
|
|
|
if (!strcmp(arg, "any")) {
|
|
|
|
ifu->fu_via_ip.s_addr = 0;
|
|
|
|
*byname = 0;
|
|
|
|
} else if (!isdigit(*arg)) {
|
|
|
|
char *q;
|
|
|
|
|
|
|
|
*byname = 1;
|
2001-06-04 23:56:26 +00:00
|
|
|
strncpy(ifu->fu_via_if.name, arg,
|
|
|
|
sizeof(ifu->fu_via_if.name));
|
1997-06-02 05:02:37 +00:00
|
|
|
ifu->fu_via_if.name[sizeof(ifu->fu_via_if.name) - 1] = '\0';
|
|
|
|
for (q = ifu->fu_via_if.name;
|
|
|
|
*q && !isdigit(*q) && *q != '*'; q++)
|
|
|
|
continue;
|
|
|
|
ifu->fu_via_if.unit = (*q == '*') ? -1 : atoi(q);
|
|
|
|
*q = '\0';
|
|
|
|
verify_interface(ifu);
|
|
|
|
} else if (!inet_aton(arg, &ifu->fu_via_ip)) {
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "bad ip address ``%s''", arg);
|
1997-06-02 05:02:37 +00:00
|
|
|
} else
|
|
|
|
*byname = 0;
|
1996-10-17 01:05:03 +00:00
|
|
|
}
|
|
|
|
|
1998-12-14 18:43:03 +00:00
|
|
|
static void
|
|
|
|
config_pipe(int ac, char **av)
|
|
|
|
{
|
2001-06-04 23:56:26 +00:00
|
|
|
struct dn_pipe pipe;
|
|
|
|
int i;
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
memset(&pipe, 0, sizeof pipe);
|
|
|
|
|
|
|
|
av++; ac--;
|
|
|
|
/* Pipe number */
|
|
|
|
if (ac && isdigit(**av)) {
|
|
|
|
i = atoi(*av); av++; ac--;
|
|
|
|
if (do_pipe == 1)
|
|
|
|
pipe.pipe_nr = i;
|
|
|
|
else
|
|
|
|
pipe.fs.fs_nr = i;
|
|
|
|
}
|
|
|
|
while (ac > 1) {
|
|
|
|
if (!strncmp(*av, "plr", strlen(*av))) {
|
|
|
|
|
|
|
|
double d = strtod(av[1], NULL);
|
|
|
|
if (d > 1)
|
|
|
|
d = 1;
|
|
|
|
else if (d < 0)
|
|
|
|
d = 0;
|
|
|
|
pipe.fs.plr = (int)(d*0x7fffffff);
|
|
|
|
av += 2;
|
|
|
|
ac -= 2;
|
|
|
|
} else if (!strncmp(*av, "queue", strlen(*av))) {
|
|
|
|
end = NULL;
|
|
|
|
pipe.fs.qsize = strtoul(av[1], &end, 0);
|
|
|
|
if (*end == 'K' || *end == 'k') {
|
|
|
|
pipe.fs.flags_fs |= DN_QSIZE_IS_BYTES;
|
|
|
|
pipe.fs.qsize *= 1024;
|
|
|
|
} else if (*end == 'B' || !strncmp(end, "by", 2)) {
|
|
|
|
pipe.fs.flags_fs |= DN_QSIZE_IS_BYTES;
|
2000-06-08 10:08:39 +00:00
|
|
|
}
|
|
|
|
av += 2;
|
|
|
|
ac -= 2;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "buckets", strlen(*av))) {
|
|
|
|
pipe.fs.rq_size = strtoul(av[1], NULL, 0);
|
2000-06-08 10:08:39 +00:00
|
|
|
av += 2;
|
|
|
|
ac -= 2;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "mask", strlen(*av))) {
|
|
|
|
/* per-flow queue, mask is dst_ip, dst_port,
|
|
|
|
* src_ip, src_port, proto measured in bits
|
|
|
|
*/
|
|
|
|
u_int32_t a;
|
|
|
|
void *par = NULL;
|
|
|
|
|
|
|
|
pipe.fs.flow_mask.dst_ip = 0;
|
|
|
|
pipe.fs.flow_mask.src_ip = 0;
|
|
|
|
pipe.fs.flow_mask.dst_port = 0;
|
|
|
|
pipe.fs.flow_mask.src_port = 0;
|
|
|
|
pipe.fs.flow_mask.proto = 0;
|
|
|
|
end = NULL;
|
|
|
|
av++; ac--;
|
|
|
|
if (ac >= 1 && !strncmp(*av, "all", strlen(*av))) {
|
|
|
|
/* special case -- all bits are significant */
|
|
|
|
pipe.fs.flow_mask.dst_ip = ~0;
|
|
|
|
pipe.fs.flow_mask.src_ip = ~0;
|
|
|
|
pipe.fs.flow_mask.dst_port = ~0;
|
|
|
|
pipe.fs.flow_mask.src_port = ~0;
|
|
|
|
pipe.fs.flow_mask.proto = ~0;
|
|
|
|
pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
|
|
|
|
av++;
|
|
|
|
ac--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
while (ac >= 1) {
|
|
|
|
int len = strlen(*av);
|
2001-10-29 00:37:24 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (!strncmp(*av, "dst-ip", len))
|
|
|
|
par = &pipe.fs.flow_mask.dst_ip;
|
|
|
|
else if (!strncmp(*av, "src-ip", len))
|
|
|
|
par = &pipe.fs.flow_mask.src_ip;
|
|
|
|
else if (!strncmp(*av, "dst-port", len))
|
|
|
|
par = &pipe.fs.flow_mask.dst_port;
|
|
|
|
else if (!strncmp(*av, "src-port", len))
|
|
|
|
par = &pipe.fs.flow_mask.src_port;
|
|
|
|
else if (!strncmp(*av, "proto", len))
|
|
|
|
par = &pipe.fs.flow_mask.proto;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
if (ac < 2)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_USAGE, "mask: %s value"
|
2001-10-29 00:37:24 +00:00
|
|
|
" missing", *av);
|
2001-06-04 23:56:26 +00:00
|
|
|
if (*av[1] == '/') {
|
|
|
|
a = strtoul(av[1]+1, &end, 0);
|
|
|
|
if (a == 32) /* special case... */
|
|
|
|
a = ~0;
|
|
|
|
else
|
|
|
|
a = (1 << a) - 1;
|
|
|
|
} else {
|
|
|
|
a = strtoul(av[1], &end, 0);
|
|
|
|
}
|
|
|
|
if (par == &pipe.fs.flow_mask.src_port
|
|
|
|
|| par == &pipe.fs.flow_mask.dst_port) {
|
|
|
|
if (a >= (1 << 16))
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "mask: %s"
|
2001-10-29 00:37:24 +00:00
|
|
|
" must be 16 bit, not"
|
|
|
|
" 0x%08x", *av, a);
|
2001-06-04 23:56:26 +00:00
|
|
|
*((u_int16_t *)par) = (u_int16_t)a;
|
|
|
|
} else if (par == &pipe.fs.flow_mask.proto) {
|
|
|
|
if (a >= (1 << 8))
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "mask: %s"
|
2001-10-29 00:37:24 +00:00
|
|
|
" must be"
|
|
|
|
" 8 bit, not 0x%08x",
|
|
|
|
*av, a);
|
2001-06-04 23:56:26 +00:00
|
|
|
*((u_int8_t *)par) = (u_int8_t)a;
|
|
|
|
} else
|
|
|
|
*((u_int32_t *)par) = a;
|
|
|
|
if (a != 0)
|
|
|
|
pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
|
|
|
|
av += 2;
|
|
|
|
ac -= 2;
|
|
|
|
} /* end for */
|
|
|
|
} else if (!strncmp(*av, "red", strlen(*av))
|
|
|
|
|| !strncmp(*av, "gred", strlen(*av))) {
|
|
|
|
/* RED enabled */
|
|
|
|
pipe.fs.flags_fs |= DN_IS_RED;
|
|
|
|
if (*av[0] == 'g')
|
|
|
|
pipe.fs.flags_fs |= DN_IS_GENTLE_RED;
|
|
|
|
if ((end = strsep(&av[1], "/"))) {
|
|
|
|
double w_q = strtod(end, NULL);
|
|
|
|
if (w_q > 1 || w_q <= 0)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "w_q %f must be "
|
2001-06-04 23:56:26 +00:00
|
|
|
"0 < x <= 1", w_q);
|
|
|
|
pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED));
|
|
|
|
}
|
|
|
|
if ((end = strsep(&av[1], "/"))) {
|
|
|
|
pipe.fs.min_th = strtoul(end, &end, 0);
|
|
|
|
if (*end == 'K' || *end == 'k')
|
|
|
|
pipe.fs.min_th *= 1024;
|
|
|
|
}
|
|
|
|
if ((end = strsep(&av[1], "/"))) {
|
|
|
|
pipe.fs.max_th = strtoul(end, &end, 0);
|
|
|
|
if (*end == 'K' || *end == 'k')
|
|
|
|
pipe.fs.max_th *= 1024;
|
|
|
|
}
|
|
|
|
if ((end = strsep(&av[1], "/"))) {
|
|
|
|
double max_p = strtod(end, NULL);
|
|
|
|
if (max_p > 1 || max_p <= 0)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "max_p %f must be "
|
2001-06-04 23:56:26 +00:00
|
|
|
"0 < x <= 1", max_p);
|
|
|
|
pipe.fs.max_p =
|
|
|
|
(int)(max_p * (1 << SCALE_RED));
|
|
|
|
}
|
|
|
|
av += 2;
|
|
|
|
ac -= 2;
|
|
|
|
} else if (!strncmp(*av, "droptail", strlen(*av))) {
|
|
|
|
/* DROPTAIL */
|
|
|
|
pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
|
|
|
|
av += 1;
|
|
|
|
ac -= 1;
|
|
|
|
} else {
|
|
|
|
int len = strlen(*av);
|
|
|
|
if (do_pipe == 1) {
|
|
|
|
/* some commands are only good for pipes. */
|
|
|
|
if (!strncmp(*av, "bw", len)
|
|
|
|
|| !strncmp(*av, "bandwidth", len)) {
|
|
|
|
if (av[1][0] >= 'a'
|
|
|
|
&& av[1][0] <= 'z') {
|
|
|
|
int l = sizeof(pipe.if_name)-1;
|
|
|
|
/* interface name */
|
|
|
|
strncpy(pipe.if_name, av[1], l);
|
|
|
|
pipe.if_name[l] = '\0';
|
|
|
|
pipe.bandwidth = 0;
|
|
|
|
} else {
|
|
|
|
pipe.if_name[0] = '\0';
|
|
|
|
pipe.bandwidth =
|
|
|
|
strtoul(av[1], &end, 0);
|
|
|
|
if (*end == 'K'
|
|
|
|
|| *end == 'k') {
|
|
|
|
end++;
|
|
|
|
pipe.bandwidth *=
|
|
|
|
1000;
|
|
|
|
} else if (*end == 'M') {
|
|
|
|
end++;
|
|
|
|
pipe.bandwidth *=
|
|
|
|
1000000;
|
|
|
|
}
|
|
|
|
if (*end == 'B'
|
|
|
|
|| !strncmp(end, "by", 2))
|
|
|
|
pipe.bandwidth *= 8;
|
|
|
|
}
|
2002-05-05 21:34:10 +00:00
|
|
|
if (pipe.bandwidth < 0)
|
|
|
|
errx(EX_DATAERR,
|
|
|
|
"bandwidth too large");
|
2001-10-29 03:25:49 +00:00
|
|
|
av += 2;
|
|
|
|
ac -= 2;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "delay", len)) {
|
|
|
|
pipe.delay = strtoul(av[1], NULL, 0);
|
2001-10-29 03:25:49 +00:00
|
|
|
av += 2;
|
|
|
|
ac -= 2;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else {
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "unrecognised pipe"
|
2001-10-29 00:37:24 +00:00
|
|
|
" option ``%s''", *av);
|
2001-06-04 23:56:26 +00:00
|
|
|
}
|
|
|
|
} else { /* this refers to a queue */
|
|
|
|
if (!strncmp(*av, "weight", len)) {
|
|
|
|
pipe.fs.weight =
|
|
|
|
strtoul(av[1], &end, 0);
|
|
|
|
av += 2;
|
|
|
|
ac -= 2;
|
|
|
|
} else if (!strncmp(*av, "pipe", len)) {
|
|
|
|
pipe.fs.parent_nr =
|
|
|
|
strtoul(av[1], &end, 0);
|
|
|
|
av += 2;
|
|
|
|
ac -= 2;
|
|
|
|
} else {
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "unrecognised option "
|
2001-06-04 23:56:26 +00:00
|
|
|
"``%s''", *av);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-06-08 10:08:39 +00:00
|
|
|
if (do_pipe == 1) {
|
2001-06-04 23:56:26 +00:00
|
|
|
if (pipe.pipe_nr == 0)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "pipe_nr %d must be > 0",
|
2001-10-29 03:25:49 +00:00
|
|
|
pipe.pipe_nr);
|
2001-06-04 23:56:26 +00:00
|
|
|
if (pipe.delay > 10000)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "delay %d must be < 10000",
|
2001-10-29 03:25:49 +00:00
|
|
|
pipe.delay);
|
2000-06-08 10:08:39 +00:00
|
|
|
} else { /* do_pipe == 2, queue */
|
2001-06-04 23:56:26 +00:00
|
|
|
if (pipe.fs.parent_nr == 0)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "pipe %d must be > 0",
|
2001-10-29 03:25:49 +00:00
|
|
|
pipe.fs.parent_nr);
|
2001-06-04 23:56:26 +00:00
|
|
|
if (pipe.fs.weight >100)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "weight %d must be <= 100",
|
2001-06-04 23:56:26 +00:00
|
|
|
pipe.fs.weight);
|
|
|
|
}
|
|
|
|
if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) {
|
|
|
|
if (pipe.fs.qsize > 1024*1024)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "queue size %d, must be < 1MB",
|
2001-06-04 23:56:26 +00:00
|
|
|
pipe.fs.qsize);
|
2000-06-08 10:08:39 +00:00
|
|
|
} else {
|
2001-06-04 23:56:26 +00:00
|
|
|
if (pipe.fs.qsize > 100)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "queue size %d, must be"
|
2001-10-29 03:25:49 +00:00
|
|
|
" 2 <= x <= 100", pipe.fs.qsize);
|
2000-06-08 10:08:39 +00:00
|
|
|
}
|
|
|
|
if (pipe.fs.flags_fs & DN_IS_RED) {
|
2002-05-05 21:34:10 +00:00
|
|
|
size_t len;
|
|
|
|
int lookup_depth, avg_pkt_size;
|
|
|
|
double s, idle, weight, w_q;
|
|
|
|
struct clockinfo clock;
|
|
|
|
int t;
|
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (pipe.fs.min_th >= pipe.fs.max_th)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "min_th %d must be < than max_th %d",
|
2001-06-04 23:56:26 +00:00
|
|
|
pipe.fs.min_th, pipe.fs.max_th);
|
|
|
|
if (pipe.fs.max_th == 0)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "max_th must be > 0");
|
2002-05-05 21:34:10 +00:00
|
|
|
|
|
|
|
len = sizeof(int);
|
|
|
|
if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
|
2000-06-08 10:08:39 +00:00
|
|
|
&lookup_depth, &len, NULL, 0) == -1)
|
|
|
|
|
2002-05-05 21:34:10 +00:00
|
|
|
errx(1, "sysctlbyname(\"%s\")",
|
|
|
|
"net.inet.ip.dummynet.red_lookup_depth");
|
|
|
|
if (lookup_depth == 0)
|
|
|
|
errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
|
|
|
|
" must be greater than zero");
|
2000-06-08 10:08:39 +00:00
|
|
|
|
2002-05-05 21:34:10 +00:00
|
|
|
len = sizeof(int);
|
|
|
|
if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
|
2000-06-08 10:08:39 +00:00
|
|
|
&avg_pkt_size, &len, NULL, 0) == -1)
|
|
|
|
|
2002-05-05 21:34:10 +00:00
|
|
|
errx(1, "sysctlbyname(\"%s\")",
|
|
|
|
"net.inet.ip.dummynet.red_avg_pkt_size");
|
|
|
|
if (avg_pkt_size == 0)
|
|
|
|
errx(EX_DATAERR,
|
|
|
|
"net.inet.ip.dummynet.red_avg_pkt_size must"
|
|
|
|
" be greater than zero");
|
|
|
|
|
|
|
|
len = sizeof(struct clockinfo);
|
|
|
|
if (sysctlbyname("kern.clockrate", &clock, &len, NULL, 0) == -1)
|
|
|
|
errx(1, "sysctlbyname(\"%s\")", "kern.clockrate");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ticks needed for sending a medium-sized packet.
|
|
|
|
* Unfortunately, when we are configuring a WF2Q+ queue, we
|
|
|
|
* do not have bandwidth information, because that is stored
|
|
|
|
* in the parent pipe, and also we have multiple queues
|
|
|
|
* competing for it. So we set s=0, which is not very
|
|
|
|
* correct. But on the other hand, why do we want RED with
|
|
|
|
* WF2Q+ ?
|
|
|
|
*/
|
|
|
|
if (pipe.bandwidth==0) /* this is a WF2Q+ queue */
|
|
|
|
s = 0;
|
|
|
|
else
|
2001-06-04 23:56:26 +00:00
|
|
|
s = clock.hz * avg_pkt_size * 8 / pipe.bandwidth;
|
|
|
|
|
2002-05-05 21:34:10 +00:00
|
|
|
/*
|
|
|
|
* max idle time (in ticks) before avg queue size becomes 0.
|
|
|
|
* NOTA: (3/w_q) is approx the value x so that
|
|
|
|
* (1-w_q)^x < 10^-3.
|
|
|
|
*/
|
|
|
|
w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED);
|
|
|
|
idle = s * 3. / w_q;
|
|
|
|
pipe.fs.lookup_step = (int)idle / lookup_depth;
|
|
|
|
if (!pipe.fs.lookup_step)
|
|
|
|
pipe.fs.lookup_step = 1;
|
|
|
|
weight = 1 - w_q;
|
|
|
|
for (t = pipe.fs.lookup_step; t > 0; --t)
|
|
|
|
weight *= weight;
|
|
|
|
pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
|
2000-06-08 10:08:39 +00:00
|
|
|
}
|
2001-06-04 23:56:26 +00:00
|
|
|
i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_CONFIGURE, &pipe,
|
|
|
|
sizeof pipe);
|
|
|
|
if (i)
|
|
|
|
err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
|
1998-12-14 18:43:03 +00:00
|
|
|
}
|
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
static void
|
|
|
|
get_mac_addr_mask(char *p, u_char *addr, u_char *mask)
|
|
|
|
{
|
|
|
|
int i, l;
|
|
|
|
|
|
|
|
for (i=0; i<6; i++)
|
|
|
|
addr[i] = mask[i] = 0;
|
|
|
|
if (!strcmp(p, "any"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i=0; *p && i<6;i++, p++) {
|
|
|
|
addr[i] = strtol(p, &p, 16);
|
|
|
|
if (*p != ':') /* we start with the mask */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (*p == '/') { /* mask len */
|
|
|
|
l = strtol(p+1, &p, 0);
|
|
|
|
for (i=0; l>0; l -=8, i++)
|
|
|
|
mask[i] = (l >=8) ? 0xff : (~0) << (8-l);
|
|
|
|
} else if (*p == '&') { /* mask */
|
|
|
|
for (i=0, p++; *p && i<6;i++, p++) {
|
|
|
|
mask[i] = strtol(p, &p, 16);
|
|
|
|
if (*p != ':')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (*p == '\0') {
|
|
|
|
for (i=0; i<6; i++)
|
|
|
|
mask[i] = 0xff;
|
|
|
|
}
|
|
|
|
for (i=0; i<6; i++)
|
|
|
|
addr[i] &= mask[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fetch and add the MAC address and type, with masks
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
add_mac(struct ip_fw *rule, int ac, char *av[])
|
|
|
|
{
|
|
|
|
u_char *addr, *mask;
|
|
|
|
u_short *type, *typemask;
|
|
|
|
int i;
|
|
|
|
char *p;
|
2002-05-13 10:19:59 +00:00
|
|
|
struct _s_x *pt;
|
2002-05-12 20:52:21 +00:00
|
|
|
|
|
|
|
if (ac <3)
|
|
|
|
errx(EX_DATAERR, "MAC dst src type");
|
|
|
|
addr = (u_char *)&(rule->fw_mac_hdr);
|
|
|
|
mask = (u_char *)&(rule->fw_mac_mask);
|
|
|
|
|
|
|
|
get_mac_addr_mask(av[0], addr, mask);
|
|
|
|
addr += 6;
|
|
|
|
mask += 6;
|
|
|
|
av++;
|
|
|
|
|
|
|
|
get_mac_addr_mask(av[0], addr, mask);
|
|
|
|
av++;
|
|
|
|
|
|
|
|
type = (u_short *)&(rule->fw_mac_type);
|
|
|
|
typemask = (u_short *)&(rule->fw_mac_mask_type);
|
|
|
|
rule->fw_flg |= IP_FW_F_MAC;
|
|
|
|
|
|
|
|
if (!strcmp(av[0], "any")) {
|
|
|
|
*type = *typemask = htons(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-05-13 10:19:59 +00:00
|
|
|
/*
|
|
|
|
* the match length is the string up to the first separator
|
|
|
|
* we know, i.e. any of "\0:/&". Note, we use bcmp instead of
|
|
|
|
* strcmp as we want an exact match.
|
|
|
|
*/
|
|
|
|
p = strpbrk(av[0], "-:/&");
|
|
|
|
if (p == NULL)
|
|
|
|
i = strlen(av[0]);
|
|
|
|
else
|
|
|
|
i = p - av[0];
|
|
|
|
for (pt = ether_types ; i && pt->s != NULL ; pt++)
|
|
|
|
if (strlen(pt->s) == i && !bcmp(*av, pt->s, i))
|
|
|
|
break;
|
|
|
|
/* store type in network format for all cases but range */
|
|
|
|
if (pt->s != NULL) {
|
|
|
|
*type = htons(pt->x);
|
|
|
|
p = av[0] + i;
|
|
|
|
} else
|
|
|
|
*type = htons( strtol(av[0], &p, 16) );
|
|
|
|
*typemask = htons(0xffff); /* default */
|
2002-05-12 20:52:21 +00:00
|
|
|
if (*p == '-') {
|
|
|
|
rule->fw_flg |= IP_FW_F_SRNG;
|
2002-05-13 10:19:59 +00:00
|
|
|
*type = ntohs(*type); /* revert to host format */
|
|
|
|
p++;
|
|
|
|
i = strlen(p);
|
|
|
|
for (pt = ether_types ; i && pt->s != NULL ; pt++)
|
|
|
|
if (strlen(pt->s) == i && !bcmp(p, pt->s, i))
|
|
|
|
break;
|
|
|
|
if (pt->s != NULL) {
|
|
|
|
*typemask = pt->x;
|
|
|
|
p += i;
|
|
|
|
} else
|
|
|
|
*typemask = strtol(p, &p, 16);
|
2002-05-12 20:52:21 +00:00
|
|
|
} else if (*p == '/') {
|
|
|
|
i = strtol(p+1, &p, 10);
|
|
|
|
if (i > 16)
|
|
|
|
errx(EX_DATAERR, "MAC: bad type %s\n", av[0]);
|
|
|
|
*typemask = htons( (~0) << (16 - i) );
|
|
|
|
*type &= *typemask;
|
|
|
|
} else if (*p == ':') {
|
|
|
|
*typemask = htons( strtol(p+1, &p, 16) );
|
|
|
|
*type &= *typemask;
|
|
|
|
}
|
|
|
|
if (*p != '\0')
|
|
|
|
errx(EX_DATAERR, "MAC: bad end type %s\n", av[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* the following macro returns an error message if we run out of
|
|
|
|
* arguments.
|
|
|
|
*/
|
|
|
|
#define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);}
|
|
|
|
|
1997-06-02 05:02:37 +00:00
|
|
|
static void
|
2001-06-04 23:56:26 +00:00
|
|
|
add(int ac, char *av[])
|
1994-10-28 15:06:53 +00:00
|
|
|
{
|
1996-02-24 00:20:56 +00:00
|
|
|
struct ip_fw rule;
|
|
|
|
int i;
|
1996-08-13 19:43:24 +00:00
|
|
|
u_char proto;
|
|
|
|
struct protoent *pe;
|
1997-06-02 05:02:37 +00:00
|
|
|
int saw_xmrc = 0, saw_via = 0;
|
2001-10-29 00:37:24 +00:00
|
|
|
|
1996-02-24 00:20:56 +00:00
|
|
|
memset(&rule, 0, sizeof rule);
|
|
|
|
|
|
|
|
av++; ac--;
|
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/* [rule N] -- Rule number optional */
|
1996-02-24 00:20:56 +00:00
|
|
|
if (ac && isdigit(**av)) {
|
|
|
|
rule.fw_number = atoi(*av); av++; ac--;
|
|
|
|
}
|
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/* [prob D] -- match probability, optional */
|
2001-06-04 23:56:26 +00:00
|
|
|
if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) {
|
1999-08-11 15:36:13 +00:00
|
|
|
double d = strtod(av[1], NULL);
|
|
|
|
if (d <= 0 || d > 1)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "illegal match prob. %s", av[1]);
|
1999-08-11 15:36:13 +00:00
|
|
|
if (d != 1) { /* 1 means always match */
|
2001-06-04 23:56:26 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_RND_MATCH;
|
2001-09-27 23:44:27 +00:00
|
|
|
rule.dont_match_prob = (long)((1 - d) * 0x7fffffff);
|
1999-08-11 15:36:13 +00:00
|
|
|
}
|
2001-06-04 23:56:26 +00:00
|
|
|
av += 2; ac -= 2;
|
1999-08-11 15:36:13 +00:00
|
|
|
}
|
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/* action -- mandatory */
|
|
|
|
NEED1("missing action");
|
2001-06-04 23:56:26 +00:00
|
|
|
if (!strncmp(*av, "accept", strlen(*av))
|
|
|
|
|| !strncmp(*av, "pass", strlen(*av))
|
|
|
|
|| !strncmp(*av, "allow", strlen(*av))
|
|
|
|
|| !strncmp(*av, "permit", strlen(*av))) {
|
1996-02-24 00:20:56 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_ACCEPT; av++; ac--;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "count", strlen(*av))) {
|
1996-02-24 00:20:56 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_COUNT; av++; ac--;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "pipe", strlen(*av))) {
|
|
|
|
rule.fw_flg |= IP_FW_F_PIPE; av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing pipe number");
|
2001-06-04 23:56:26 +00:00
|
|
|
rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "queue", strlen(*av))) {
|
|
|
|
rule.fw_flg |= IP_FW_F_QUEUE; av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing queue number");
|
2001-06-04 23:56:26 +00:00
|
|
|
rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "divert", strlen(*av))) {
|
1996-07-10 19:44:30 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_DIVERT; av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing divert port");
|
1996-07-10 19:44:30 +00:00
|
|
|
rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
|
1997-07-25 03:13:46 +00:00
|
|
|
if (rule.fw_divert_port == 0) {
|
|
|
|
struct servent *s;
|
|
|
|
setservent(1);
|
|
|
|
s = getservbyname(av[-1], "divert");
|
|
|
|
if (s != NULL)
|
|
|
|
rule.fw_divert_port = ntohs(s->s_port);
|
|
|
|
else
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "illegal %s port", "divert");
|
1997-07-25 03:13:46 +00:00
|
|
|
}
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "tee", strlen(*av))) {
|
1997-06-02 05:02:37 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_TEE; av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing tee divert port");
|
1997-06-02 05:02:37 +00:00
|
|
|
rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
|
1997-07-25 03:13:46 +00:00
|
|
|
if (rule.fw_divert_port == 0) {
|
|
|
|
struct servent *s;
|
|
|
|
setservent(1);
|
|
|
|
s = getservbyname(av[-1], "divert");
|
|
|
|
if (s != NULL)
|
|
|
|
rule.fw_divert_port = ntohs(s->s_port);
|
|
|
|
else
|
2001-10-29 00:37:24 +00:00
|
|
|
errx(EX_DATAERR, "illegal %s port",
|
2001-10-29 03:46:28 +00:00
|
|
|
"tee divert");
|
1997-07-25 03:13:46 +00:00
|
|
|
}
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "fwd", strlen(*av))
|
|
|
|
|| !strncmp(*av, "forward", strlen(*av))) {
|
1998-07-06 03:20:19 +00:00
|
|
|
struct in_addr dummyip;
|
|
|
|
char *pp;
|
|
|
|
rule.fw_flg |= IP_FW_F_FWD; av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing forwarding IP address");
|
1998-07-06 03:20:19 +00:00
|
|
|
rule.fw_fwd_ip.sin_len = sizeof(struct sockaddr_in);
|
|
|
|
rule.fw_fwd_ip.sin_family = AF_INET;
|
|
|
|
rule.fw_fwd_ip.sin_port = 0;
|
|
|
|
pp = strchr(*av, ':');
|
2002-05-12 20:52:21 +00:00
|
|
|
if( pp == NULL)
|
1998-07-06 03:20:19 +00:00
|
|
|
pp = strchr(*av, ',');
|
2002-05-12 20:52:21 +00:00
|
|
|
if (pp != NULL) {
|
1998-07-06 03:20:19 +00:00
|
|
|
*(pp++) = '\0';
|
2000-10-04 07:59:19 +00:00
|
|
|
i = lookup_port(pp, 0, 1, 0);
|
1999-06-11 09:43:53 +00:00
|
|
|
if (i == -1)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "illegal forwarding"
|
2001-10-29 03:46:28 +00:00
|
|
|
" port ``%s''", pp);
|
1999-06-11 09:43:53 +00:00
|
|
|
else
|
|
|
|
rule.fw_fwd_ip.sin_port = (u_short)i;
|
1998-07-06 03:20:19 +00:00
|
|
|
}
|
|
|
|
fill_ip(&(rule.fw_fwd_ip.sin_addr), &dummyip, &ac, &av);
|
|
|
|
if (rule.fw_fwd_ip.sin_addr.s_addr == 0)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "illegal forwarding IP address");
|
1998-07-06 03:20:19 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "skipto", strlen(*av))) {
|
1997-06-02 05:02:37 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_SKIPTO; av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing skipto rule number");
|
2001-09-19 15:12:14 +00:00
|
|
|
rule.fw_skipto_rule = strtoul(*av, NULL, 10); av++; ac--;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if ((!strncmp(*av, "deny", strlen(*av))
|
|
|
|
|| !strncmp(*av, "drop", strlen(*av)))) {
|
1996-07-10 19:44:30 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_DENY; av++; ac--;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "reject", strlen(*av))) {
|
1997-06-02 05:02:37 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
|
|
|
|
rule.fw_reject_code = ICMP_UNREACH_HOST;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "reset", strlen(*av))) {
|
1997-06-02 05:02:37 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
|
|
|
|
rule.fw_reject_code = IP_FW_REJECT_RST; /* check TCP later */
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "unreach", strlen(*av))) {
|
1997-06-02 05:02:37 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
|
|
|
|
fill_reject_code(&rule.fw_reject_code, *av); av++; ac--;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "check-state", strlen(*av))) {
|
|
|
|
rule.fw_flg |= IP_FW_F_CHECK_S; av++; ac--;
|
|
|
|
goto done;
|
1996-02-24 00:20:56 +00:00
|
|
|
} else {
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "invalid action ``%s''", *av);
|
1994-10-28 15:06:53 +00:00
|
|
|
}
|
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/* [log [logamount N]] -- log, optional */
|
2001-06-04 23:56:26 +00:00
|
|
|
if (ac && !strncmp(*av, "log", strlen(*av))) {
|
2002-05-12 20:52:21 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_PRN; av++; ac--;
|
|
|
|
if (ac && !strncmp(*av, "logamount", strlen(*av))) {
|
1999-08-01 16:57:24 +00:00
|
|
|
ac--; av++;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("``logamount'' requires argument");
|
1999-08-01 16:57:24 +00:00
|
|
|
rule.fw_logamount = atoi(*av);
|
2000-04-30 06:44:11 +00:00
|
|
|
if (rule.fw_logamount < 0)
|
2002-05-12 20:52:21 +00:00
|
|
|
errx(EX_DATAERR, "``logamount'' argument must be positive");
|
2000-04-30 06:44:11 +00:00
|
|
|
if (rule.fw_logamount == 0)
|
2002-05-12 20:52:21 +00:00
|
|
|
rule.fw_logamount = -1;
|
1999-08-01 16:57:24 +00:00
|
|
|
ac--; av++;
|
2002-05-12 20:52:21 +00:00
|
|
|
}
|
1999-08-01 16:57:24 +00:00
|
|
|
}
|
1994-10-28 15:06:53 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/* protocol -- mandatory */
|
|
|
|
NEED1("missing protocol");
|
|
|
|
|
|
|
|
if (!strncmp(*av, "MAC", strlen(*av))) {
|
|
|
|
ac--;
|
|
|
|
av++;
|
|
|
|
/* need exactly 3 fields */
|
|
|
|
add_mac(&rule, ac, av); /* exits in case of errors */
|
|
|
|
ac -= 3;
|
|
|
|
av += 3;
|
|
|
|
goto do_options;
|
|
|
|
} else if ((proto = atoi(*av)) > 0) {
|
1997-06-02 05:02:37 +00:00
|
|
|
rule.fw_prot = proto; av++; ac--;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "all", strlen(*av))) {
|
1997-06-02 05:02:37 +00:00
|
|
|
rule.fw_prot = IPPROTO_IP; av++; ac--;
|
|
|
|
} else if ((pe = getprotobyname(*av)) != NULL) {
|
|
|
|
rule.fw_prot = pe->p_proto; av++; ac--;
|
|
|
|
} else {
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "invalid protocol ``%s''", *av);
|
1997-06-02 05:02:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rule.fw_prot != IPPROTO_TCP
|
|
|
|
&& (rule.fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
|
|
|
|
&& rule.fw_reject_code == IP_FW_REJECT_RST)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "``reset'' is only valid for tcp packets");
|
1994-10-28 15:06:53 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/* from -- mandatory */
|
|
|
|
if (!ac || strncmp(*av, "from", strlen(*av)))
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_USAGE, "missing ``from''");
|
2002-05-12 20:52:21 +00:00
|
|
|
av++; ac--;
|
1994-10-28 15:06:53 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/* not -- optional */
|
2001-06-04 23:56:26 +00:00
|
|
|
if (ac && !strncmp(*av, "not", strlen(*av))) {
|
1997-01-17 07:01:21 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_INVSRC;
|
1997-01-16 21:04:29 +00:00
|
|
|
av++; ac--;
|
|
|
|
}
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing source address");
|
1997-01-16 21:04:29 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/* source -- mandatory */
|
|
|
|
if (!strncmp(*av, "me", strlen(*av))) {
|
2001-02-13 14:12:37 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_SME;
|
|
|
|
av++; ac--;
|
|
|
|
} else {
|
|
|
|
fill_ip(&rule.fw_src, &rule.fw_smsk, &ac, &av);
|
|
|
|
}
|
1994-10-28 15:06:53 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/* ports -- optional */
|
2001-06-04 23:56:26 +00:00
|
|
|
if (ac && (isdigit(**av)
|
|
|
|
|| lookup_port(*av, rule.fw_prot, 1, 1) >= 0)) {
|
1997-06-02 05:02:37 +00:00
|
|
|
u_short nports = 0;
|
2001-06-04 23:56:26 +00:00
|
|
|
int retval;
|
1997-06-02 05:02:37 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
retval = fill_port(&nports, rule.fw_uar.fw_pts,
|
|
|
|
0, *av, rule.fw_prot);
|
2000-01-08 11:19:19 +00:00
|
|
|
if (retval == 1)
|
1996-02-24 00:20:56 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_SRNG;
|
2000-01-08 11:19:19 +00:00
|
|
|
else if (retval == 2)
|
|
|
|
rule.fw_flg |= IP_FW_F_SMSK;
|
1997-06-02 05:02:37 +00:00
|
|
|
IP_FW_SETNSRCP(&rule, nports);
|
1996-02-24 00:20:56 +00:00
|
|
|
av++; ac--;
|
1994-10-28 15:06:53 +00:00
|
|
|
}
|
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/* to -- mandatory */
|
|
|
|
if (!ac || strncmp(*av, "to", strlen(*av)))
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_USAGE, "missing ``to''");
|
2002-05-12 20:52:21 +00:00
|
|
|
av++; ac--;
|
1995-10-01 21:54:05 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/* not -- optional */
|
2001-06-04 23:56:26 +00:00
|
|
|
if (ac && !strncmp(*av, "not", strlen(*av))) {
|
1997-01-17 07:01:21 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_INVDST;
|
1997-01-16 21:04:29 +00:00
|
|
|
av++; ac--;
|
|
|
|
}
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing dst address");
|
1995-10-01 21:54:05 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/* destination -- mandatory */
|
|
|
|
if (!strncmp(*av, "me", strlen(*av))) {
|
2001-02-13 14:12:37 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_DME;
|
|
|
|
av++; ac--;
|
|
|
|
} else {
|
|
|
|
fill_ip(&rule.fw_dst, &rule.fw_dmsk, &ac, &av);
|
|
|
|
}
|
1995-10-01 21:54:05 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/* dest.ports -- optional */
|
2001-06-04 23:56:26 +00:00
|
|
|
if (ac && (isdigit(**av)
|
|
|
|
|| lookup_port(*av, rule.fw_prot, 1, 1) >= 0)) {
|
1997-06-02 05:02:37 +00:00
|
|
|
u_short nports = 0;
|
2001-06-04 23:56:26 +00:00
|
|
|
int retval;
|
1997-06-02 05:02:37 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
retval = fill_port(&nports, rule.fw_uar.fw_pts,
|
|
|
|
IP_FW_GETNSRCP(&rule), *av, rule.fw_prot);
|
2000-01-08 11:19:19 +00:00
|
|
|
if (retval == 1)
|
1996-02-24 00:20:56 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_DRNG;
|
2000-01-08 11:19:19 +00:00
|
|
|
else if (retval == 2)
|
|
|
|
rule.fw_flg |= IP_FW_F_DMSK;
|
1997-06-02 05:02:37 +00:00
|
|
|
IP_FW_SETNDSTP(&rule, nports);
|
1996-02-24 00:20:56 +00:00
|
|
|
av++; ac--;
|
1995-10-01 21:54:05 +00:00
|
|
|
}
|
|
|
|
|
1997-06-02 05:02:37 +00:00
|
|
|
if ((rule.fw_prot != IPPROTO_TCP) && (rule.fw_prot != IPPROTO_UDP)
|
|
|
|
&& (IP_FW_GETNSRCP(&rule) || IP_FW_GETNDSTP(&rule))) {
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_USAGE, "only TCP and UDP protocols are valid"
|
1997-06-02 05:02:37 +00:00
|
|
|
" with port specifications");
|
1996-02-24 13:39:46 +00:00
|
|
|
}
|
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
do_options:
|
1996-02-24 00:20:56 +00:00
|
|
|
while (ac) {
|
2001-06-04 23:56:26 +00:00
|
|
|
if (!strncmp(*av, "uid", strlen(*av))) {
|
1999-06-19 18:43:33 +00:00
|
|
|
struct passwd *pwd;
|
1999-09-03 18:18:46 +00:00
|
|
|
char *end;
|
|
|
|
uid_t uid;
|
1999-06-19 18:43:33 +00:00
|
|
|
|
|
|
|
rule.fw_flg |= IP_FW_F_UID;
|
|
|
|
ac--; av++;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("``uid'' requires argument");
|
2001-10-29 00:37:24 +00:00
|
|
|
|
1999-09-03 18:18:46 +00:00
|
|
|
uid = strtoul(*av, &end, 0);
|
|
|
|
if (*end == '\0')
|
|
|
|
pwd = getpwuid(uid);
|
|
|
|
else
|
|
|
|
pwd = getpwnam(*av);
|
|
|
|
if (pwd == NULL)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "uid \"%s\" is"
|
|
|
|
" nonexistent", *av);
|
1999-09-03 18:18:46 +00:00
|
|
|
rule.fw_uid = pwd->pw_uid;
|
1999-06-19 18:43:33 +00:00
|
|
|
ac--; av++;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "gid", strlen(*av))) {
|
1999-06-19 18:43:33 +00:00
|
|
|
struct group *grp;
|
1999-09-03 18:18:46 +00:00
|
|
|
char *end;
|
|
|
|
gid_t gid;
|
1999-06-19 18:43:33 +00:00
|
|
|
|
|
|
|
rule.fw_flg |= IP_FW_F_GID;
|
|
|
|
ac--; av++;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("``gid'' requires argument");
|
2001-10-29 00:37:24 +00:00
|
|
|
|
1999-09-03 18:18:46 +00:00
|
|
|
gid = strtoul(*av, &end, 0);
|
|
|
|
if (*end == '\0')
|
|
|
|
grp = getgrgid(gid);
|
|
|
|
else
|
|
|
|
grp = getgrnam(*av);
|
|
|
|
if (grp == NULL)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "gid \"%s\" is"
|
|
|
|
" nonexistent", *av);
|
1999-09-03 18:18:46 +00:00
|
|
|
rule.fw_gid = grp->gr_gid;
|
1999-06-19 18:43:33 +00:00
|
|
|
ac--; av++;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "in", strlen(*av))) {
|
1997-06-02 05:02:37 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_IN;
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
2001-09-27 23:44:27 +00:00
|
|
|
} else if (!strncmp(*av,"limit",strlen(*av))) {
|
2001-11-04 23:19:46 +00:00
|
|
|
/* dyn. rule used to limit number of connections. */
|
|
|
|
rule.fw_flg |= IP_FW_F_KEEP_S;
|
|
|
|
rule.dyn_type = DYN_LIMIT ;
|
|
|
|
rule.limit_mask = 0 ;
|
|
|
|
av++; ac--;
|
|
|
|
for (; ac >1 ;) {
|
|
|
|
struct _s_x *p = limit_masks;
|
2002-05-12 20:52:21 +00:00
|
|
|
for ( ; p->x != 0 ; p++)
|
2001-11-04 23:19:46 +00:00
|
|
|
if (!strncmp(*av, p->s, strlen(*av))) {
|
|
|
|
rule.limit_mask |= p->x ;
|
|
|
|
av++; ac-- ;
|
|
|
|
break ;
|
|
|
|
}
|
|
|
|
if (p->s == NULL)
|
2001-11-01 08:45:02 +00:00
|
|
|
break ;
|
2001-11-04 23:19:46 +00:00
|
|
|
}
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("limit needs mask and # of connections");
|
2001-11-04 23:19:46 +00:00
|
|
|
rule.conn_limit = atoi(*av);
|
|
|
|
if (rule.conn_limit == 0)
|
|
|
|
errx(EX_USAGE, "limit: limit must be >0");
|
|
|
|
if (rule.limit_mask == 0)
|
|
|
|
errx(EX_USAGE, "missing limit mask");
|
|
|
|
av++; ac--;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "keep-state", strlen(*av))) {
|
|
|
|
u_long type;
|
|
|
|
rule.fw_flg |= IP_FW_F_KEEP_S;
|
|
|
|
|
|
|
|
av++; ac--;
|
|
|
|
if (ac > 0 && (type = atoi(*av)) != 0) {
|
2001-11-04 23:19:46 +00:00
|
|
|
rule.dyn_type = type;
|
|
|
|
av++; ac--;
|
2001-06-04 23:56:26 +00:00
|
|
|
}
|
|
|
|
} else if (!strncmp(*av, "bridged", strlen(*av))) {
|
|
|
|
rule.fw_flg |= IP_FW_BRIDGED;
|
|
|
|
av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "out", strlen(*av))) {
|
1997-06-02 05:02:37 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_OUT;
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
} else if (!strncmp(*av, "xmit", strlen(*av))) {
|
1997-06-02 05:02:37 +00:00
|
|
|
union ip_fw_if ifu;
|
|
|
|
int byname;
|
|
|
|
|
|
|
|
if (saw_via) {
|
|
|
|
badviacombo:
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_USAGE, "``via'' is incompatible"
|
1997-06-02 05:02:37 +00:00
|
|
|
" with ``xmit'' and ``recv''");
|
1996-06-29 01:28:19 +00:00
|
|
|
}
|
1997-06-02 05:02:37 +00:00
|
|
|
saw_xmrc = 1;
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
1997-06-02 05:02:37 +00:00
|
|
|
fill_iface("xmit", &ifu, &byname, ac, *av);
|
|
|
|
rule.fw_out_if = ifu;
|
|
|
|
rule.fw_flg |= IP_FW_F_OIFACE;
|
|
|
|
if (byname)
|
|
|
|
rule.fw_flg |= IP_FW_F_OIFNAME;
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
} else if (!strncmp(*av, "recv", strlen(*av))) {
|
1997-06-02 05:02:37 +00:00
|
|
|
union ip_fw_if ifu;
|
|
|
|
int byname;
|
|
|
|
|
|
|
|
if (saw_via)
|
|
|
|
goto badviacombo;
|
|
|
|
saw_xmrc = 1;
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
1997-06-02 05:02:37 +00:00
|
|
|
fill_iface("recv", &ifu, &byname, ac, *av);
|
|
|
|
rule.fw_in_if = ifu;
|
|
|
|
rule.fw_flg |= IP_FW_F_IIFACE;
|
|
|
|
if (byname)
|
|
|
|
rule.fw_flg |= IP_FW_F_IIFNAME;
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
} else if (!strncmp(*av, "via", strlen(*av))) {
|
1997-06-02 05:02:37 +00:00
|
|
|
union ip_fw_if ifu;
|
|
|
|
int byname = 0;
|
|
|
|
|
|
|
|
if (saw_xmrc)
|
|
|
|
goto badviacombo;
|
|
|
|
saw_via = 1;
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
1997-06-02 05:02:37 +00:00
|
|
|
fill_iface("via", &ifu, &byname, ac, *av);
|
|
|
|
rule.fw_out_if = rule.fw_in_if = ifu;
|
|
|
|
if (byname)
|
|
|
|
rule.fw_flg |=
|
|
|
|
(IP_FW_F_IIFNAME | IP_FW_F_OIFNAME);
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "fragment", strlen(*av))) {
|
1997-06-02 05:02:37 +00:00
|
|
|
rule.fw_flg |= IP_FW_F_FRAG;
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "ipoptions", strlen(*av))
|
|
|
|
|| !strncmp(*av, "ipopts", strlen(*av))) {
|
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing argument for ``ipoptions''");
|
2000-10-02 03:03:31 +00:00
|
|
|
rule.fw_ipflg |= IP_FW_IF_IPOPT;
|
2002-05-12 20:52:21 +00:00
|
|
|
fill_flags(&rule.fw_ipopt, &rule.fw_ipnopt,
|
|
|
|
f_ipopts, av);
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "iplen", strlen(*av))) {
|
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing argument for ``iplen''");
|
2001-06-04 23:56:26 +00:00
|
|
|
rule.fw_ipflg |= IP_FW_IF_IPLEN;
|
|
|
|
rule.fw_iplen = (u_short)strtoul(*av, NULL, 0);
|
|
|
|
av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "ipid", strlen(*av))) {
|
2000-10-03 11:23:29 +00:00
|
|
|
unsigned long ipid;
|
|
|
|
char *c;
|
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing argument for ``ipid''");
|
2000-10-03 11:23:29 +00:00
|
|
|
ipid = strtoul(*av, &c, 0);
|
|
|
|
if (*c != '\0')
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "argument to ipid must"
|
|
|
|
" be numeric");
|
2000-10-03 11:23:29 +00:00
|
|
|
if (ipid > 65535)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "argument to ipid out"
|
|
|
|
" of range");
|
2001-06-04 23:56:26 +00:00
|
|
|
rule.fw_ipflg |= IP_FW_IF_IPID;
|
|
|
|
rule.fw_ipid = (u_short)ipid;
|
|
|
|
av++; ac--;
|
2001-12-21 18:43:37 +00:00
|
|
|
} else if (!strncmp(*av, "ipprecedence", strlen(*av))) {
|
|
|
|
u_long ippre;
|
|
|
|
char *c;
|
|
|
|
|
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing argument for ``ipprecedence''");
|
2001-12-21 18:43:37 +00:00
|
|
|
ippre = strtoul(*av, &c, 0);
|
|
|
|
if (*c != '\0')
|
|
|
|
errx(EX_DATAERR, "argument to ipprecedence"
|
|
|
|
" must be numeric");
|
|
|
|
if (ippre > 7)
|
|
|
|
errx(EX_DATAERR, "argument to ipprecedence"
|
|
|
|
" out of range");
|
|
|
|
rule.fw_ipflg |= IP_FW_IF_IPPRE;
|
|
|
|
rule.fw_iptos |= (u_short)(ippre << 5);
|
|
|
|
av++; ac--;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (!strncmp(*av, "iptos", strlen(*av))) {
|
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing argument for ``iptos''");
|
2001-06-04 23:56:26 +00:00
|
|
|
rule.fw_ipflg |= IP_FW_IF_IPTOS;
|
2002-05-12 20:52:21 +00:00
|
|
|
fill_flags(&rule.fw_iptos, &rule.fw_ipntos,
|
|
|
|
f_iptos, av);
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "ipttl", strlen(*av))) {
|
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing argument for ``ipttl''");
|
2001-06-04 23:56:26 +00:00
|
|
|
rule.fw_ipflg |= IP_FW_IF_IPTTL;
|
|
|
|
rule.fw_ipttl = (u_short)strtoul(*av, NULL, 0);
|
|
|
|
av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "ipversion", strlen(*av))
|
|
|
|
|| !strncmp(*av, "ipver", strlen(*av))) {
|
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing argument for ``ipversion''");
|
2001-06-04 23:56:26 +00:00
|
|
|
rule.fw_ipflg |= IP_FW_IF_IPVER;
|
|
|
|
rule.fw_ipver = (u_short)strtoul(*av, NULL, 0);
|
|
|
|
av++; ac--;
|
|
|
|
} else if (rule.fw_prot == IPPROTO_TCP) {
|
|
|
|
if (!strncmp(*av, "established", strlen(*av))) {
|
o IPFW incorrectly handled filtering in the presence of previously
reserved and now allocated TCP flags in incoming packets. This patch
stops overloading those bits in the IP firewall rules, and moves
colliding flags to a seperate field, ipflg. The IPFW userland
management tool, ipfw(8), is updated to reflect this change. New TCP
flags related to ECN are now included in tcp.h for reference, although
we don't currently implement TCP+ECN.
o To use this fix without completely rebuilding, it is sufficient to copy
ip_fw.h and tcp.h into your appropriate include directory, then rebuild
the ipfw kernel module, and ipfw tool, and install both. Note that a
mismatch between module and userland tool will result in incorrect
installation of firewall rules that may have unexpected effects. This
is an MFC candidate, following shakedown. This bug does not appear
to affect ipfilter.
Reviewed by: security-officer, billf
Reported by: Aragon Gouveia <aragon@phat.za.net>
2001-01-09 03:10:30 +00:00
|
|
|
rule.fw_ipflg |= IP_FW_IF_TCPEST;
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "setup", strlen(*av))) {
|
2002-05-13 10:19:59 +00:00
|
|
|
rule.fw_tcpf |= TH_SYN;
|
|
|
|
rule.fw_tcpnf |= TH_ACK;
|
2001-06-04 23:56:26 +00:00
|
|
|
rule.fw_ipflg |= IP_FW_IF_TCPFLG;
|
|
|
|
av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "tcpflags", strlen(*av))
|
|
|
|
|| !strncmp(*av, "tcpflgs", strlen(*av))) {
|
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing argument for ``tcpflags''");
|
2001-06-04 23:56:26 +00:00
|
|
|
rule.fw_ipflg |= IP_FW_IF_TCPFLG;
|
2002-05-12 20:52:21 +00:00
|
|
|
fill_flags(&rule.fw_tcpf,
|
|
|
|
&rule.fw_tcpnf, f_tcpflags, av);
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "tcpoptions", strlen(*av))
|
|
|
|
|| !strncmp(*av, "tcpopts", strlen(*av))) {
|
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing argument for ``tcpoptions''");
|
2001-06-04 23:56:26 +00:00
|
|
|
rule.fw_ipflg |= IP_FW_IF_TCPOPT;
|
2002-05-12 20:52:21 +00:00
|
|
|
fill_flags(&rule.fw_tcpopt,
|
|
|
|
&rule.fw_tcpnopt, f_tcpopts, av);
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "tcpseq", strlen(*av))) {
|
2000-10-02 03:03:31 +00:00
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing argument for ``tcpseq''");
|
2001-06-04 23:56:26 +00:00
|
|
|
rule.fw_ipflg |= IP_FW_IF_TCPSEQ;
|
|
|
|
rule.fw_tcpseq =
|
|
|
|
htonl(strtoul(*av, NULL, 0));
|
|
|
|
av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "tcpack", strlen(*av))) {
|
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing argument for ``tcpack''");
|
2001-06-04 23:56:26 +00:00
|
|
|
rule.fw_ipflg |= IP_FW_IF_TCPACK;
|
|
|
|
rule.fw_tcpack =
|
|
|
|
htonl(strtoul(*av, NULL, 0));
|
|
|
|
av++; ac--;
|
|
|
|
} else if (!strncmp(*av, "tcpwin", strlen(*av))) {
|
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing argument for ``tcpwin''");
|
2001-06-04 23:56:26 +00:00
|
|
|
rule.fw_ipflg |= IP_FW_IF_TCPWIN;
|
|
|
|
rule.fw_tcpwin =
|
|
|
|
htons((u_short)strtoul(*av, NULL, 0));
|
|
|
|
av++; ac--;
|
2001-07-10 05:44:51 +00:00
|
|
|
} else
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_USAGE, "unknown or out of order"
|
|
|
|
" argument ``%s''", *av);
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if (rule.fw_prot == IPPROTO_ICMP) {
|
|
|
|
if (!strncmp(*av, "icmptypes", strlen(*av))) {
|
1996-06-09 23:46:22 +00:00
|
|
|
av++; ac--;
|
2002-05-12 20:52:21 +00:00
|
|
|
NEED1("missing argument for ``icmptypes''");
|
1998-01-08 03:03:54 +00:00
|
|
|
fill_icmptypes(rule.fw_uar.fw_icmptypes,
|
1997-06-02 05:02:37 +00:00
|
|
|
av, &rule.fw_flg);
|
2001-06-04 23:56:26 +00:00
|
|
|
av++; ac--;
|
2001-07-10 05:44:51 +00:00
|
|
|
} else
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_USAGE, "unknown or out of"
|
|
|
|
" order argument ``%s''", *av);
|
2001-07-10 05:44:51 +00:00
|
|
|
} else
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_USAGE, "unknown argument ``%s''", *av);
|
1994-11-16 10:18:18 +00:00
|
|
|
}
|
1994-10-28 15:06:53 +00:00
|
|
|
|
1997-06-02 05:02:37 +00:00
|
|
|
/* No direction specified -> do both directions */
|
|
|
|
if (!(rule.fw_flg & (IP_FW_F_OUT|IP_FW_F_IN)))
|
|
|
|
rule.fw_flg |= (IP_FW_F_OUT|IP_FW_F_IN);
|
|
|
|
|
|
|
|
/* Sanity check interface check, but handle "via" case separately */
|
|
|
|
if (saw_via) {
|
|
|
|
if (rule.fw_flg & IP_FW_F_IN)
|
|
|
|
rule.fw_flg |= IP_FW_F_IIFACE;
|
|
|
|
if (rule.fw_flg & IP_FW_F_OUT)
|
|
|
|
rule.fw_flg |= IP_FW_F_OIFACE;
|
2001-06-04 23:56:26 +00:00
|
|
|
} else if ((rule.fw_flg & IP_FW_F_OIFACE)
|
|
|
|
&& (rule.fw_flg & IP_FW_F_IN)) {
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "can't check xmit interface of incoming"
|
|
|
|
" packets");
|
2001-06-04 23:56:26 +00:00
|
|
|
}
|
1997-06-02 05:02:37 +00:00
|
|
|
|
1998-02-12 00:57:06 +00:00
|
|
|
/* frag may not be used in conjunction with ports or TCP flags */
|
|
|
|
if (rule.fw_flg & IP_FW_F_FRAG) {
|
|
|
|
if (rule.fw_tcpf || rule.fw_tcpnf)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "can't mix 'frag' and tcpflags");
|
1998-02-12 00:57:06 +00:00
|
|
|
|
|
|
|
if (rule.fw_nports)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "can't mix 'frag' and port"
|
|
|
|
" specifications");
|
1998-02-12 00:57:06 +00:00
|
|
|
}
|
1999-08-01 16:57:24 +00:00
|
|
|
if (rule.fw_flg & IP_FW_F_PRN) {
|
|
|
|
if (!rule.fw_logamount) {
|
|
|
|
size_t len = sizeof(int);
|
|
|
|
|
|
|
|
if (sysctlbyname("net.inet.ip.fw.verbose_limit",
|
|
|
|
&rule.fw_logamount, &len, NULL, 0) == -1)
|
|
|
|
errx(1, "sysctlbyname(\"%s\")",
|
|
|
|
"net.inet.ip.fw.verbose_limit");
|
2000-04-30 06:44:11 +00:00
|
|
|
} else if (rule.fw_logamount == -1)
|
|
|
|
rule.fw_logamount = 0;
|
1999-08-01 16:57:24 +00:00
|
|
|
rule.fw_loghighest = rule.fw_logamount;
|
|
|
|
}
|
2000-02-10 14:25:26 +00:00
|
|
|
done:
|
2000-10-12 07:59:14 +00:00
|
|
|
i = sizeof(rule);
|
|
|
|
if (getsockopt(s, IPPROTO_IP, IP_FW_ADD, &rule, &i) == -1)
|
|
|
|
err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
|
1997-02-10 15:36:54 +00:00
|
|
|
if (!do_quiet)
|
2001-06-04 23:56:26 +00:00
|
|
|
show_ipfw(&rule);
|
1994-10-28 15:06:53 +00:00
|
|
|
}
|
|
|
|
|
1997-06-02 05:02:37 +00:00
|
|
|
static void
|
2001-06-04 23:56:26 +00:00
|
|
|
zero (int ac, char *av[])
|
1996-06-09 23:46:22 +00:00
|
|
|
{
|
2001-06-04 23:56:26 +00:00
|
|
|
struct ip_fw rule;
|
|
|
|
int failed = EX_OK;
|
2001-10-29 00:37:24 +00:00
|
|
|
|
1996-06-09 23:46:22 +00:00
|
|
|
av++; ac--;
|
|
|
|
|
|
|
|
if (!ac) {
|
|
|
|
/* clear all entries */
|
2001-06-04 23:56:26 +00:00
|
|
|
if (setsockopt(s, IPPROTO_IP, IP_FW_ZERO, NULL, 0) < 0)
|
1998-01-07 02:23:04 +00:00
|
|
|
err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_ZERO");
|
1997-02-10 15:36:54 +00:00
|
|
|
if (!do_quiet)
|
|
|
|
printf("Accounting cleared.\n");
|
2001-06-04 23:56:26 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&rule, 0, sizeof rule);
|
|
|
|
while (ac) {
|
|
|
|
/* Rule number */
|
|
|
|
if (isdigit(**av)) {
|
|
|
|
rule.fw_number = atoi(*av); av++; ac--;
|
|
|
|
if (setsockopt(s, IPPROTO_IP,
|
|
|
|
IP_FW_ZERO, &rule, sizeof rule)) {
|
|
|
|
warn("rule %u: setsockopt(IP_FW_ZERO)",
|
|
|
|
rule.fw_number);
|
|
|
|
failed = EX_UNAVAILABLE;
|
2001-10-29 03:25:49 +00:00
|
|
|
} else if (!do_quiet)
|
2001-06-04 23:56:26 +00:00
|
|
|
printf("Entry %d cleared\n",
|
|
|
|
rule.fw_number);
|
|
|
|
} else {
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_USAGE, "invalid rule number ``%s''", *av);
|
1996-06-09 23:46:22 +00:00
|
|
|
}
|
|
|
|
}
|
2001-06-04 23:56:26 +00:00
|
|
|
if (failed != EX_OK)
|
|
|
|
exit(failed);
|
1996-06-09 23:46:22 +00:00
|
|
|
}
|
|
|
|
|
1999-08-01 16:57:24 +00:00
|
|
|
static void
|
2001-06-04 23:56:26 +00:00
|
|
|
resetlog (int ac, char *av[])
|
1999-08-01 16:57:24 +00:00
|
|
|
{
|
2001-06-04 23:56:26 +00:00
|
|
|
struct ip_fw rule;
|
|
|
|
int failed = EX_OK;
|
2001-10-29 00:37:24 +00:00
|
|
|
|
1999-08-01 16:57:24 +00:00
|
|
|
av++; ac--;
|
|
|
|
|
|
|
|
if (!ac) {
|
|
|
|
/* clear all entries */
|
2001-06-04 23:56:26 +00:00
|
|
|
if (setsockopt(s, IPPROTO_IP, IP_FW_RESETLOG, NULL, 0) < 0)
|
|
|
|
err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)");
|
1999-08-01 16:57:24 +00:00
|
|
|
if (!do_quiet)
|
|
|
|
printf("Logging counts reset.\n");
|
2001-06-04 23:56:26 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&rule, 0, sizeof rule);
|
|
|
|
while (ac) {
|
|
|
|
/* Rule number */
|
|
|
|
if (isdigit(**av)) {
|
|
|
|
rule.fw_number = atoi(*av); av++; ac--;
|
|
|
|
if (setsockopt(s, IPPROTO_IP,
|
|
|
|
IP_FW_RESETLOG, &rule, sizeof rule)) {
|
|
|
|
warn("rule %u: setsockopt(IP_FW_RESETLOG)",
|
|
|
|
rule.fw_number);
|
|
|
|
failed = EX_UNAVAILABLE;
|
|
|
|
} else if (!do_quiet)
|
|
|
|
printf("Entry %d logging count reset\n",
|
|
|
|
rule.fw_number);
|
|
|
|
} else {
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_DATAERR, "invalid rule number ``%s''", *av);
|
1999-08-01 16:57:24 +00:00
|
|
|
}
|
|
|
|
}
|
2001-06-04 23:56:26 +00:00
|
|
|
if (failed != EX_OK)
|
|
|
|
exit(failed);
|
1999-08-01 16:57:24 +00:00
|
|
|
}
|
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
static void
|
|
|
|
flush()
|
|
|
|
{
|
|
|
|
if (!do_force && !do_quiet) { /* need to ask user */
|
|
|
|
int c;
|
|
|
|
|
|
|
|
printf("Are you sure? [yn] ");
|
|
|
|
fflush(stdout);
|
|
|
|
do {
|
|
|
|
c = toupper(getc(stdin));
|
|
|
|
while (c != '\n' && getc(stdin) != '\n')
|
|
|
|
if (feof(stdin))
|
|
|
|
return; /* and do not flush */
|
|
|
|
} while (c != 'Y' && c != 'N');
|
|
|
|
printf("\n");
|
|
|
|
if (c == 'N') /* user said no */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (setsockopt(s, IPPROTO_IP,
|
|
|
|
do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH, NULL, 0) < 0)
|
|
|
|
err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)",
|
|
|
|
do_pipe ? "DUMMYNET" : "FW");
|
|
|
|
if (!do_quiet)
|
|
|
|
printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules");
|
|
|
|
}
|
|
|
|
|
1998-09-28 22:56:37 +00:00
|
|
|
static int
|
2001-06-04 23:56:26 +00:00
|
|
|
ipfw_main(int ac, char **av)
|
1994-11-16 10:18:18 +00:00
|
|
|
{
|
2001-06-04 23:56:26 +00:00
|
|
|
int ch;
|
1994-10-28 15:06:53 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (ac == 1)
|
2001-07-22 06:40:11 +00:00
|
|
|
show_usage();
|
2000-10-11 13:02:30 +00:00
|
|
|
|
1996-08-31 17:58:23 +00:00
|
|
|
/* Set the force flag for non-interactive processes */
|
|
|
|
do_force = !isatty(STDIN_FILENO);
|
|
|
|
|
1998-11-23 10:54:28 +00:00
|
|
|
optind = optreset = 1;
|
2001-06-04 23:56:26 +00:00
|
|
|
while ((ch = getopt(ac, av, "s:adefNqtv")) != -1)
|
2002-05-12 20:52:21 +00:00
|
|
|
switch (ch) {
|
|
|
|
case 's': /* sort */
|
|
|
|
do_sort = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
do_acct = 1;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
do_dynamic = 1;
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
do_expired = 1;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
do_force = 1;
|
|
|
|
break;
|
|
|
|
case 'N':
|
|
|
|
do_resolv = 1;
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
do_quiet = 1;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
do_time = 1;
|
|
|
|
break;
|
|
|
|
case 'v': /* verbose */
|
|
|
|
verbose++;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
show_usage();
|
|
|
|
}
|
1994-10-28 15:06:53 +00:00
|
|
|
|
1996-02-24 00:20:56 +00:00
|
|
|
ac -= optind;
|
2002-05-12 20:52:21 +00:00
|
|
|
av += optind;
|
|
|
|
if (*av == NULL)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_USAGE, "bad arguments, for usage summary ``ipfw''");
|
1994-10-28 15:06:53 +00:00
|
|
|
|
2001-06-04 23:56:26 +00:00
|
|
|
if (!strncmp(*av, "pipe", strlen(*av))) {
|
|
|
|
do_pipe = 1;
|
|
|
|
ac--;
|
|
|
|
av++;
|
|
|
|
} else if (!strncmp(*av, "queue", strlen(*av))) {
|
|
|
|
do_pipe = 2;
|
|
|
|
ac--;
|
|
|
|
av++;
|
|
|
|
}
|
|
|
|
if (!ac)
|
2001-07-22 06:40:11 +00:00
|
|
|
errx(EX_USAGE, "pipe requires arguments");
|
2001-06-04 23:56:26 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
/* allow argument swapping -- pipe config xxx or pipe xxx config */
|
2001-06-04 23:56:26 +00:00
|
|
|
if (ac > 1 && *av[0] >= '0' && *av[0] <= '9') {
|
|
|
|
char *p = av[0];
|
|
|
|
av[0] = av[1];
|
|
|
|
av[1] = p;
|
1998-12-27 11:23:05 +00:00
|
|
|
}
|
2002-05-12 20:52:21 +00:00
|
|
|
if (!strncmp(*av, "add", strlen(*av)))
|
2001-06-04 23:56:26 +00:00
|
|
|
add(ac, av);
|
2002-05-12 20:52:21 +00:00
|
|
|
else if (do_pipe && !strncmp(*av, "config", strlen(*av)))
|
2001-06-04 23:56:26 +00:00
|
|
|
config_pipe(ac, av);
|
2002-05-12 20:52:21 +00:00
|
|
|
else if (!strncmp(*av, "delete", strlen(*av)))
|
2001-06-04 23:56:26 +00:00
|
|
|
delete(ac, av);
|
2002-05-12 20:52:21 +00:00
|
|
|
else if (!strncmp(*av, "flush", strlen(*av)))
|
|
|
|
flush();
|
|
|
|
else if (!strncmp(*av, "zero", strlen(*av)))
|
2001-06-04 23:56:26 +00:00
|
|
|
zero(ac, av);
|
2002-05-12 20:52:21 +00:00
|
|
|
else if (!strncmp(*av, "resetlog", strlen(*av)))
|
2001-06-04 23:56:26 +00:00
|
|
|
resetlog(ac, av);
|
2002-05-12 20:52:21 +00:00
|
|
|
else if (!strncmp(*av, "print", strlen(*av)))
|
2001-06-04 23:56:26 +00:00
|
|
|
list(--ac, ++av);
|
2002-05-12 20:52:21 +00:00
|
|
|
else if (!strncmp(*av, "list", strlen(*av)))
|
2001-06-04 23:56:26 +00:00
|
|
|
list(--ac, ++av);
|
2002-05-12 20:52:21 +00:00
|
|
|
else if (!strncmp(*av, "show", strlen(*av))) {
|
1997-02-10 15:36:54 +00:00
|
|
|
do_acct++;
|
2001-06-04 23:56:26 +00:00
|
|
|
list(--ac, ++av);
|
2002-05-12 20:52:21 +00:00
|
|
|
} else
|
|
|
|
errx(EX_USAGE, "bad command `%s'", *av);
|
1996-06-23 20:47:51 +00:00
|
|
|
return 0;
|
1994-11-16 10:18:18 +00:00
|
|
|
}
|
1994-10-28 15:06:53 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
ipfw_readfile(int ac, char *av[])
|
1995-10-23 03:58:06 +00:00
|
|
|
{
|
|
|
|
#define MAX_ARGS 32
|
1997-06-02 05:02:37 +00:00
|
|
|
#define WHITESP " \t\f\v\n\r"
|
1996-02-24 13:39:46 +00:00
|
|
|
char buf[BUFSIZ];
|
1998-11-23 10:54:28 +00:00
|
|
|
char *a, *p, *args[MAX_ARGS], *cmd = NULL;
|
1995-10-23 03:58:06 +00:00
|
|
|
char linename[10];
|
2002-05-12 20:52:21 +00:00
|
|
|
int i=0, lineno=0, qflag=0, pflag=0, status;
|
1998-11-23 10:54:28 +00:00
|
|
|
FILE *f = NULL;
|
|
|
|
pid_t preproc = 0;
|
2002-05-12 20:52:21 +00:00
|
|
|
int c;
|
|
|
|
|
2002-12-23 20:08:21 +00:00
|
|
|
while ((c = getopt(ac, av, "p:q")) != -1) {
|
2002-05-12 20:52:21 +00:00
|
|
|
switch(c) {
|
|
|
|
case 'p':
|
|
|
|
pflag = 1;
|
|
|
|
cmd = optarg;
|
|
|
|
args[0] = cmd;
|
|
|
|
i = 1;
|
|
|
|
break;
|
1996-02-24 00:20:56 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
case 'q':
|
|
|
|
qflag = 1;
|
|
|
|
break;
|
2000-02-10 14:25:26 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
default:
|
|
|
|
errx(EX_USAGE, "bad arguments, for usage"
|
|
|
|
" summary ``ipfw''");
|
|
|
|
}
|
1998-11-23 10:54:28 +00:00
|
|
|
|
2002-12-23 20:08:21 +00:00
|
|
|
if (pflag)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pflag) {
|
|
|
|
/* Pass all but the last argument to the preprocessor. */
|
|
|
|
while (optind < ac - 1) {
|
|
|
|
if (i >= MAX_ARGS)
|
|
|
|
errx(EX_USAGE, "too many preprocessor options");
|
|
|
|
args[i++] = av[optind++];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
av += optind;
|
|
|
|
ac -= optind;
|
|
|
|
if (ac != 1)
|
|
|
|
errx(EX_USAGE, "extraneous filename arguments");
|
1998-11-23 10:54:28 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
if ((f = fopen(av[0], "r")) == NULL)
|
|
|
|
err(EX_UNAVAILABLE, "fopen: %s", av[0]);
|
1998-11-23 10:54:28 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
if (pflag) {
|
|
|
|
/* pipe through preprocessor (cpp or m4) */
|
|
|
|
int pipedes[2];
|
1998-11-23 10:54:28 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
args[i] = 0;
|
1998-11-23 10:54:28 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
if (pipe(pipedes) == -1)
|
|
|
|
err(EX_OSERR, "cannot create pipe");
|
|
|
|
|
|
|
|
switch((preproc = fork())) {
|
|
|
|
case -1:
|
|
|
|
err(EX_OSERR, "cannot fork");
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
/* child */
|
|
|
|
if (dup2(fileno(f), 0) == -1
|
|
|
|
|| dup2(pipedes[1], 1) == -1)
|
|
|
|
err(EX_OSERR, "dup2()");
|
|
|
|
fclose(f);
|
|
|
|
close(pipedes[1]);
|
|
|
|
close(pipedes[0]);
|
|
|
|
execvp(cmd, args);
|
|
|
|
err(EX_OSERR, "execvp(%s) failed", cmd);
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* parent */
|
|
|
|
fclose(f);
|
|
|
|
close(pipedes[1]);
|
|
|
|
if ((f = fdopen(pipedes[0], "r")) == NULL) {
|
|
|
|
int savederrno = errno;
|
|
|
|
|
|
|
|
(void)kill(preproc, SIGTERM);
|
|
|
|
errno = savederrno;
|
|
|
|
err(EX_OSERR, "fdopen()");
|
1998-11-23 10:54:28 +00:00
|
|
|
}
|
|
|
|
}
|
2002-05-12 20:52:21 +00:00
|
|
|
}
|
1998-11-23 10:54:28 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
while (fgets(buf, BUFSIZ, f)) {
|
|
|
|
lineno++;
|
|
|
|
sprintf(linename, "Line %d", lineno);
|
|
|
|
args[0] = linename;
|
1995-10-23 03:58:06 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
if (*buf == '#')
|
|
|
|
continue;
|
|
|
|
if ((p = strchr(buf, '#')) != NULL)
|
|
|
|
*p = '\0';
|
|
|
|
i = 1;
|
|
|
|
if (qflag)
|
|
|
|
args[i++] = "-q";
|
|
|
|
for (a = strtok(buf, WHITESP);
|
|
|
|
a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++)
|
|
|
|
args[i] = a;
|
|
|
|
if (i == (qflag? 2: 1))
|
|
|
|
continue;
|
|
|
|
if (i == MAX_ARGS)
|
|
|
|
errx(EX_USAGE, "%s: too many arguments",
|
|
|
|
linename);
|
|
|
|
args[i] = NULL;
|
|
|
|
|
|
|
|
ipfw_main(i, args);
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
if (pflag) {
|
|
|
|
if (waitpid(preproc, &status, 0) == -1)
|
|
|
|
errx(EX_OSERR, "waitpid()");
|
|
|
|
if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
|
|
|
|
errx(EX_UNAVAILABLE,
|
|
|
|
"preprocessor exited with status %d",
|
|
|
|
WEXITSTATUS(status));
|
|
|
|
else if (WIFSIGNALED(status))
|
|
|
|
errx(EX_UNAVAILABLE,
|
|
|
|
"preprocessor exited with signal %d",
|
|
|
|
WTERMSIG(status));
|
|
|
|
}
|
|
|
|
}
|
1994-10-28 15:06:53 +00:00
|
|
|
|
2002-05-12 20:52:21 +00:00
|
|
|
int
|
|
|
|
main(int ac, char *av[])
|
|
|
|
{
|
|
|
|
s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
|
|
|
|
if (s < 0)
|
|
|
|
err(EX_UNAVAILABLE, "socket");
|
|
|
|
|
|
|
|
setbuf(stdout, 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Only interpret the last command line argument as a file to
|
|
|
|
* be preprocessed if it is specified as an absolute pathname.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0)
|
|
|
|
ipfw_readfile(ac, av);
|
|
|
|
else
|
2001-06-04 23:56:26 +00:00
|
|
|
ipfw_main(ac, av);
|
1998-01-07 02:23:04 +00:00
|
|
|
return EX_OK;
|
1995-10-23 03:58:06 +00:00
|
|
|
}
|