+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
/*
* Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
* Copyright (c) 1994 Ugen J.S.Antsilevich
*
* NEW command line interface for IP firewall facility
*
- * $Id: ipfw.c,v 1.2 2000/06/07 04:22:47 lindak Exp $
- *
*/
-#include <sys/types.h>
-#include <sys/queue.h>
+
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
+#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/wait.h>
+#include <sys/ioctl.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
+#include <grp.h>
#include <limits.h>
#include <netdb.h>
+#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
-#include <sysexits.h>
-#include <time.h>
#include <unistd.h>
+#include <sysexits.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
-#include <netinet/ip_var.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip_fw.h>
#include <net/route.h> /* def. of struct route */
-#include <sys/param.h>
-#include <sys/mbuf.h>
+#ifdef DUMMYNET
#include <netinet/ip_dummynet.h>
+#endif /* DUMMYNET */
#include <netinet/tcp.h>
#include <arpa/inet.h>
-int lineno = -1;
-
-int s; /* main RAW socket */
-int do_resolv=0; /* Would try to resolve all */
-int do_acct=0; /* Show packet/byte count */
-int do_time=0; /* Show time stamps */
-int do_quiet=0; /* Be quiet in add and flush */
-int do_force=0; /* Don't ask for confirmation */
-int do_pipe=0; /* this cmd refers to a pipe */
+int s, /* main RAW socket */
+ do_resolv, /* Would try to resolve all */
+ do_acct, /* Show packet/byte count */
+ do_time, /* Show time stamps */
+ do_quiet, /* Be quiet in add and flush */
+ do_force, /* Don't ask for confirmation */
+ #ifdef DUMMYNET
+ do_pipe, /* this cmd refers to a pipe */
+ #endif /* DUMMYNET */
+ do_sort, /* field to sort results (0 = no) */
+ verbose;
struct icmpcode {
int code;
{ ICMP_UNREACH_TOSHOST, "toshost" },
{ ICMP_UNREACH_FILTER_PROHIB, "filter-prohib" },
{ ICMP_UNREACH_HOST_PRECEDENCE, "host-precedence" },
- { ICMP_UNREACH_PRECEDENCE_CUTOFF, "precedence-cutoff" },
+ { ICMP_UNREACH_PRECEDENCE_CUTOFF, "precedence-cutoff" },
{ 0, NULL }
};
static int
mask_bits(struct in_addr m_ad)
{
- int h_fnd=0,h_num=0,i;
+ int h_fnd = 0, h_num = 0, i;
u_long mask;
- mask=ntohl(m_ad.s_addr);
- for (i=0;i<sizeof(u_long)*CHAR_BIT;i++) {
+ mask = ntohl(m_ad.s_addr);
+ for (i = 0; i < sizeof(u_long) * CHAR_BIT; i++) {
if (mask & 1L) {
- h_fnd=1;
+ h_fnd = 1;
h_num++;
} else {
if (h_fnd)
return -1;
}
- mask=mask>>1;
+ mask = mask >> 1;
}
return h_num;
-}
+}
static void
print_port(prot, port, comma)
const char *protocol;
int printed = 0;
+ if (!strcmp(comma, ":")) {
+ printf("%s0x%04x", comma, port);
+ return;
+ }
if (do_resolv) {
pe = getprotobynumber(prot);
if (pe)
printf("%s%s", comma, se->s_name);
printed = 1;
}
- }
+ }
if (!printed)
- printf("%s%d",comma,port);
+ printf("%s%d", comma, port);
}
static void
if (byname) {
strncpy(ifnb, un->fu_via_if.name, FW_IFNLEN);
- ifnb[FW_IFNLEN]='\0';
+ ifnb[FW_IFNLEN] = '\0';
if (un->fu_via_if.unit == -1)
printf(" %s %s*", key, ifnb);
- else
+ else
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));
int ndp = IP_FW_GETNDSTP(chain);
if (do_resolv)
- setservent(1/*stayopen*/);
+ setservent(1/*stay open*/);
printf("%05u ", chain->fw_number);
- if (do_acct)
- printf("%*qu %*qu ",pcwidth,chain->fw_pcnt,bcwidth,chain->fw_bcnt);
+ if (do_acct)
+ printf("%*qu %*qu ", pcwidth, chain->fw_pcnt, bcwidth, chain->fw_bcnt);
- if (do_time)
- {
- if (chain->timestamp)
- {
+ if (do_time) {
+ if (chain->timestamp) {
char timestr[30];
strcpy(timestr, ctime((time_t *)&chain->timestamp));
*strchr(timestr, '\n') = '\0';
printf("%s ", timestr);
+ } else {
+ printf(" ");
}
- else
- printf(" ");
+ }
+ if (chain->fw_flg == IP_FW_F_CHECK_S) {
+ printf("check-state\n");
+ goto done;
}
- switch (chain->fw_flg & IP_FW_F_COMMAND)
- {
+ if (chain->fw_flg & IP_FW_F_RND_MATCH) {
+ double d = 1.0 * (int)(chain->pipe_ptr);
+ d = 1 - (d / 0x7fffffff);
+ printf("prob %f ", d);
+ }
+
+ switch (chain->fw_flg & IP_FW_F_COMMAND) {
case IP_FW_F_ACCEPT:
printf("allow");
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_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");
default:
errx(EX_OSERR, "impossible");
}
-
- if (chain->fw_flg & IP_FW_F_PRN)
+
+ if (chain->fw_flg & IP_FW_F_PRN) {
printf(" log");
+ if (chain->fw_logamount)
+ printf(" logamount %d", chain->fw_logamount);
+ }
pe = getprotobynumber(chain->fw_prot);
if (pe)
else
printf(" %u", chain->fw_prot);
- printf(" from %s", chain->fw_flg & IP_FW_F_INVSRC ? "not " : "");
-
- adrt=ntohl(chain->fw_smsk.s_addr);
- if (adrt==ULONG_MAX && do_resolv) {
- adrt=(chain->fw_src.s_addr);
- he=gethostbyaddr((char *)&adrt,sizeof(u_long),AF_INET);
- if (he==NULL) {
- printf(inet_ntoa(chain->fw_src));
- } else
- printf("%s",he->h_name);
+ if (chain->fw_flg & IP_FW_F_SME) {
+ printf(" from me");
} else {
- if (adrt!=ULONG_MAX) {
- mb=mask_bits(chain->fw_smsk);
- if (mb == 0) {
- printf("any");
- } else {
- if (mb > 0) {
- printf(inet_ntoa(chain->fw_src));
- printf("/%d",mb);
+ printf(" from %s", chain->fw_flg & IP_FW_F_INVSRC ? "not " : "");
+
+ adrt = ntohl(chain->fw_smsk.s_addr);
+ if (adrt == ULONG_MAX && do_resolv) {
+ adrt = (chain->fw_src.s_addr);
+ he = gethostbyaddr((char *)&adrt,
+ sizeof(u_long), AF_INET);
+ if (he == NULL) {
+ printf("%s", inet_ntoa(chain->fw_src));
+ } else
+ printf("%s", he->h_name);
+ } else {
+ if (adrt != ULONG_MAX) {
+ mb = mask_bits(chain->fw_smsk);
+ if (mb == 0) {
+ printf("any");
} else {
- printf(inet_ntoa(chain->fw_src));
- printf(":");
- printf(inet_ntoa(chain->fw_smsk));
+ if (mb > 0) {
+ printf("%s", inet_ntoa(chain->fw_src));
+ printf("/%d", mb);
+ } else {
+ printf("%s", inet_ntoa(chain->fw_src));
+ printf(":");
+ printf("%s", inet_ntoa(chain->fw_smsk));
+ }
}
- }
- } else
- printf(inet_ntoa(chain->fw_src));
+ } else
+ printf("%s", inet_ntoa(chain->fw_src));
+ }
}
if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
comma = " ";
for (i = 0; i < nsp; i++) {
print_port(chain->fw_prot, chain->fw_uar.fw_pts[i], comma);
- if (i==0 && (chain->fw_flg & IP_FW_F_SRNG))
+ if (i == 0 && (chain->fw_flg & IP_FW_F_SRNG))
comma = "-";
+ else if (i == 0 && (chain->fw_flg & IP_FW_F_SMSK))
+ comma = ":";
else
comma = ",";
}
}
- printf(" to %s", chain->fw_flg & IP_FW_F_INVDST ? "not " : "");
-
- adrt=ntohl(chain->fw_dmsk.s_addr);
- if (adrt==ULONG_MAX && do_resolv) {
- adrt=(chain->fw_dst.s_addr);
- he=gethostbyaddr((char *)&adrt,sizeof(u_long),AF_INET);
- if (he==NULL) {
- printf(inet_ntoa(chain->fw_dst));
- } else
- printf("%s",he->h_name);
+ if (chain->fw_flg & IP_FW_F_DME) {
+ printf(" to me");
} else {
- if (adrt!=ULONG_MAX) {
- mb=mask_bits(chain->fw_dmsk);
- if (mb == 0) {
- printf("any");
- } else {
- if (mb > 0) {
- printf(inet_ntoa(chain->fw_dst));
- printf("/%d",mb);
+ printf(" to %s", chain->fw_flg & IP_FW_F_INVDST ? "not " : "");
+
+ adrt = ntohl(chain->fw_dmsk.s_addr);
+ if (adrt == ULONG_MAX && do_resolv) {
+ adrt = (chain->fw_dst.s_addr);
+ he = gethostbyaddr((char *)&adrt,
+ sizeof(u_long), AF_INET);
+ if (he == NULL) {
+ printf("%s", inet_ntoa(chain->fw_dst));
+ } else
+ printf("%s", he->h_name);
+ } else {
+ if (adrt != ULONG_MAX) {
+ mb = mask_bits(chain->fw_dmsk);
+ if (mb == 0) {
+ printf("any");
} else {
- printf(inet_ntoa(chain->fw_dst));
- printf(":");
- printf(inet_ntoa(chain->fw_dmsk));
+ if (mb > 0) {
+ printf("%s", inet_ntoa(chain->fw_dst));
+ printf("/%d", mb);
+ } else {
+ printf("%s", inet_ntoa(chain->fw_dst));
+ printf(":");
+ printf("%s", inet_ntoa(chain->fw_dmsk));
+ }
}
- }
- } else
- printf(inet_ntoa(chain->fw_dst));
+ } else
+ printf("%s", inet_ntoa(chain->fw_dst));
+ }
}
if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
comma = " ";
for (i = 0; i < ndp; i++) {
print_port(chain->fw_prot, chain->fw_uar.fw_pts[nsp+i], comma);
- if (i==0 && (chain->fw_flg & IP_FW_F_DRNG))
+ if (i == 0 && (chain->fw_flg & IP_FW_F_DRNG))
comma = "-";
+ else if (i == 0 && (chain->fw_flg & IP_FW_F_DMSK))
+ comma = ":";
else
comma = ",";
}
}
+ 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_KEEP_S) {
+ if (chain->next_rule_ptr)
+ printf(" keep-state %d", (int)chain->next_rule_ptr);
+ else
+ printf(" keep-state");
+ }
/* Direction */
+ if (chain->fw_flg & IP_FW_BRIDGED)
+ printf(" bridged");
if ((chain->fw_flg & IP_FW_F_IN) && !(chain->fw_flg & IP_FW_F_OUT))
printf(" in");
if (!(chain->fw_flg & IP_FW_F_IN) && (chain->fw_flg & IP_FW_F_OUT))
if (chain->fw_ipnopt & IP_FW_IPOPT_RR) PRINTOPT("!rr");
if (chain->fw_ipopt & IP_FW_IPOPT_TS) PRINTOPT("ts");
if (chain->fw_ipnopt & IP_FW_IPOPT_TS) PRINTOPT("!ts");
- }
+ }
- if (chain->fw_tcpf & IP_FW_TCPF_ESTAB)
+ if (chain->fw_ipflg & IP_FW_IF_TCPEST)
printf(" established");
else if (chain->fw_tcpf == IP_FW_TCPF_SYN &&
chain->fw_tcpnf == IP_FW_TCPF_ACK)
#define PRINTFLG(x) {if (_flg_printed) printf(",");\
printf(x); _flg_printed = 1;}
- printf(" tcpflg ");
+ printf(" tcpflags ");
if (chain->fw_tcpf & IP_FW_TCPF_FIN) PRINTFLG("fin");
if (chain->fw_tcpnf & IP_FW_TCPF_FIN) PRINTFLG("!fin");
if (chain->fw_tcpf & IP_FW_TCPF_SYN) PRINTFLG("syn");
if (chain->fw_tcpnf & IP_FW_TCPF_ACK) PRINTFLG("!ack");
if (chain->fw_tcpf & IP_FW_TCPF_URG) PRINTFLG("urg");
if (chain->fw_tcpnf & IP_FW_TCPF_URG) PRINTFLG("!urg");
- }
+ }
+ if (chain->fw_tcpopt || chain->fw_tcpnopt) {
+ int _opt_printed = 0;
+#define PRINTTOPT(x) {if (_opt_printed) printf(",");\
+ printf(x); _opt_printed = 1;}
+
+ printf(" tcpoptions ");
+ if (chain->fw_tcpopt & IP_FW_TCPOPT_MSS) PRINTTOPT("mss");
+ if (chain->fw_tcpnopt & IP_FW_TCPOPT_MSS) PRINTTOPT("!mss");
+ if (chain->fw_tcpopt & IP_FW_TCPOPT_WINDOW) PRINTTOPT("window");
+ if (chain->fw_tcpnopt & IP_FW_TCPOPT_WINDOW) PRINTTOPT("!window");
+ if (chain->fw_tcpopt & IP_FW_TCPOPT_SACK) PRINTTOPT("sack");
+ if (chain->fw_tcpnopt & IP_FW_TCPOPT_SACK) PRINTTOPT("!sack");
+ if (chain->fw_tcpopt & IP_FW_TCPOPT_TS) PRINTTOPT("ts");
+ if (chain->fw_tcpnopt & IP_FW_TCPOPT_TS) PRINTTOPT("!ts");
+ if (chain->fw_tcpopt & IP_FW_TCPOPT_CC) PRINTTOPT("cc");
+ if (chain->fw_tcpnopt & IP_FW_TCPOPT_CC) PRINTTOPT("!cc");
+ }
+
if (chain->fw_flg & IP_FW_F_ICMPBIT) {
int type_index;
int first = 1;
printf(" icmptype");
for (type_index = 0; type_index < IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8; ++type_index)
- if (chain->fw_uar.fw_icmptypes[type_index / (sizeof(unsigned) * 8)] &
+ if (chain->fw_uar.fw_icmptypes[type_index / (sizeof(unsigned) * 8)] &
(1U << (type_index % (sizeof(unsigned) * 8)))) {
printf("%c%d", first == 1 ? ' ' : ',', type_index);
first = 0;
}
}
printf("\n");
+done:
if (do_resolv)
endservent();
}
+#ifdef DUMMYNET
+int
+sort_q(const void *pa, const void *pb)
+{
+ 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);
+}
+
+static void
+list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
+{
+ int l;
+
+ 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;
+
+ 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);
+ }
+}
+
+static void
+print_flowset_parms(struct dn_flow_set *fs, char *prefix)
+{
+ int l;
+ char qs[30];
+ char plr[30];
+ char red[90]; /* Display RED parameters */
+
+ 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';
+ if (fs->flags_fs & DN_IS_RED) /* RED parameters */
+ sprintf(red,
+ "\n %cRED w_q %f min_th %d max_th %d max_p %f",
+ (fs->flags_fs & DN_IS_GENTLE_RED)? 'G' : ' ',
+ 1.0 * fs->w_q / (double)(1 << SCALE_RED),
+ SCALE_VAL(fs->min_th),
+ SCALE_VAL(fs->max_th),
+ 1.0 * fs->max_p / (double)(1 << SCALE_RED) ) ;
+ else
+ sprintf(red, "droptail");
+
+ printf("%s %s%s %d queues (%d buckets) %s\n", prefix, qs, plr,
+ fs->rq_elements, fs->rq_size, red);
+}
+#endif /* DUMMYNET */
+
static void
list(ac, av)
int ac;
char **av;
{
struct ip_fw *rules;
+ #ifdef DUMMYNET
struct dn_pipe *pipes;
+ #endif /* DUMMYNET */
void *data = NULL;
int pcwidth = 0;
int bcwidth = 0;
int n, num = 0;
+ int nbytes;
/* get rules or pipes from kernel, resizing array as necessary */
{
+ #ifdef DUMMYNET
const int unit = do_pipe ? sizeof(*pipes) : sizeof(*rules);
const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET;
- int nalloc = 0;
- int nbytes;
-
- while (num >= nalloc) {
+ #else /* DUMMYNET */
+ const int unit = sizeof(*rules);
+ const int ocmd = IP_FW_GET;
+ #endif /* DUMMYNET */
+ int nalloc = unit;
+ nbytes = nalloc;
+
+ while (nbytes >= nalloc) {
nalloc = nalloc * 2 + 200;
- nbytes = nalloc * unit;
+ nbytes = nalloc;
if ((data = realloc(data, nbytes)) == NULL)
err(EX_OSERR, "realloc");
+ rules = data;
+ rules->version = IP_FW_CURRENT_API_VERSION;
if (getsockopt(s, IPPROTO_IP, ocmd, data, &nbytes) < 0)
+ #ifdef DUMMYNET
err(EX_OSERR, "getsockopt(IP_%s_GET)",
do_pipe ? "DUMMYNET" : "FW");
- num = nbytes / unit;
+ #else /* DUMMYNET */
+ err(EX_OSERR, "getsockopt(IP_FW_GET)");
+ #endif /* DUMMYNET */
}
}
/* display requested pipes */
+ #ifdef DUMMYNET
if (do_pipe) {
- u_long rulenum;
-
- pipes = (struct dn_pipe *) data;
- if (ac > 0)
- rulenum = strtoul(*av++, NULL, 10);
- else
- rulenum = 0 ;
- for (n = 0; n < num; n++) {
- struct dn_pipe *const p = &pipes[n];
- double b = p->bandwidth ;
- char buf[30] ;
- char qs[30] ;
- char plr[30] ;
- int l ;
-
- if (rulenum != 0 && rulenum != p->pipe_nr)
- continue;
- 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 );
-
- if ( (l = p->queue_size_bytes) != 0 ) {
- if (l >= 8192)
- sprintf(qs,"%d KB", l / 1024);
- else
- sprintf(qs,"%d B", l);
- } else
- sprintf(qs,"%3d sl.", p->queue_size);
- if (p->plr)
- sprintf(plr,"plr %f", 1.0*p->plr/(double)(0x7fffffff));
+ 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;
+
+ if (ac > 0)
+ rulenum = strtoul(*av++, NULL, 10);
else
- plr[0]='\0';
+ rulenum = 0;
+ for (; nbytes >= sizeof(*p); p = (struct dn_pipe *)next) {
+ double b = p->bandwidth;
+ char buf[30];
+ char prefix[80];
- printf("%05d: %s %4d ms %s %s -- %d pkts (%d B) %d drops\n",
- p->pipe_nr, buf, p->delay, qs, plr,
- p->r_len, p->r_len_bytes, p->r_drops);
- }
- free(data);
- return;
+ if (p->next != (struct dn_pipe *)DN_IS_PIPE)
+ break;
+ l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
+ next = (void *)p + l;
+ nbytes -= l;
+ q = (struct dn_flow_queue *)(p+1);
+
+ 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);
+
+ 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];
+
+ if (fs->next != (struct dn_flow_set *)DN_IS_QUEUE)
+ break;
+ l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
+ next = (void *)fs + l;
+ 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);
+ }
+ free(data);
+ return;
}
+ #endif /* DUMMYNET */
- /* if showing stats, figure out column widths ahead of time */
rules = (struct ip_fw *) data;
+ /* determine num more accurately */
+ num = 0;
+ while (rules[num].fw_number < 65535)
+ num++;
+ num++; /* counting starts from 0 ... */
+ /* if showing stats, figure out column widths ahead of time */
if (do_acct) {
for (n = 0; n < num; n++) {
struct ip_fw *const r = &rules[n];
if (exitval != EX_OK)
exit(exitval);
}
+ /*
+ * show dynamic rules
+ */
+ if (num * sizeof (rules[0]) != nbytes) {
+ struct ipfw_dyn_rule *d =
+ (struct ipfw_dyn_rule *)&rules[num];
+ struct in_addr a;
+ struct protoent *pe;
+
+ printf("## Dynamic rules:\n");
+ for (;; d++) {
+ printf("%05d %qu %qu (T %d, # %d) ty %d",
+ (int)(d->chain),
+ d->pcnt, d->bcnt,
+ d->expire,
+ d->bucket,
+ d->type);
+ pe = getprotobynumber(d->id.proto);
+ if (pe)
+ printf(" %s,", pe->p_name);
+ else
+ printf(" %u,", d->id.proto);
+ a.s_addr = htonl(d->id.src_ip);
+ printf(" %s", inet_ntoa(a));
+ printf(" %d", d->id.src_port);
+ switch (d->type) {
+ default: /* bidir, no mask */
+ printf(" <->");
+ break;
+ }
+ a.s_addr = htonl(d->id.dst_ip);
+ printf(" %s", inet_ntoa(a));
+ printf(" %d", d->id.dst_port);
+ printf("\n");
+ if (d->next == NULL)
+ break;
+ }
+ }
+
free(data);
}
warnx("error: %s", buf);
}
fprintf(stderr, "usage: ipfw [options]\n"
-" flush\n"
+#ifdef DUMMYNET
+" [pipe] flush\n"
+#endif /* DUMMYNET */
" add [number] rule\n"
-" delete number ...\n"
-" list [number ...]\n"
-" show [number ...]\n"
+#ifdef DUMMYNET
+" [pipe] delete number ...\n"
+" [pipe] list [number ...]\n"
+" [pipe] show [number ...]\n"
+#endif /* DUMMYNET */
" zero [number ...]\n"
-" rule: action proto src dst extras...\n"
+" resetlog [number ...]\n"
+#ifdef DUMMYNET
+" pipe number config [pipeconfig]\n"
+#endif /* DUMMYNET */
+" rule: [prob <match_probability>] action proto src dst extras...\n"
" action:\n"
" {allow|permit|accept|pass|deny|drop|reject|unreach code|\n"
-" reset|count|skipto num|divert port|tee port|fwd ip} [log]\n"
+" reset|count|skipto num|divert port|tee port|fwd ip|\n"
+#ifdef DUMMYNET
+" pipe num"
+#endif /* DUMMYNET */
+"} [log [logamount count]]\n"
" proto: {ip|tcp|udp|icmp|<number>}\n"
-" src: from [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
-" dst: to [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
+" src: from [not] {me|any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
+" dst: to [not] {me|any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
" extras:\n"
+" uid {user id}\n"
" fragment (may not be used with ports or tcpflags)\n"
" in\n"
" out\n"
" {established|setup}\n"
" tcpflags [!]{syn|fin|rst|ack|psh|urg},...\n"
" ipoptions [!]{ssrr|lsrr|rr|ts},...\n"
-" icmptypes {type[,type]}...\n");
+" tcpoptions [!]{mss|window|sack|ts|cc},...\n"
+" icmptypes {type[,type]}...\n"
+#ifdef DUMMYNET
+" pipeconfig:\n"
+" {bw|bandwidth} <number>{bit/s|Kbit/s|Mbit/s|Bytes/s|KBytes/s|MBytes/s}\n"
+" {bw|bandwidth} interface_name\n"
+" delay <milliseconds>\n"
+" queue <size>{packets|Bytes|KBytes}\n"
+" plr <fraction>\n"
+" mask {all| [dst-ip|src-ip|dst-port|src-port|proto] <number>}\n"
+" buckets <number>}\n"
+" {red|gred} <fraction>/<number>/<number>/<fraction>\n"
+" droptail\n"
+#endif /* DUMMYNET */
+);
exit(EX_USAGE);
}
char *host;
struct in_addr *ipaddr;
{
- struct hostent *he = gethostbyname(host);
-
- if (!he) {
- if (inet_aton(host, ipaddr))
- return(0);
- else
- return(-1);
- }
- *ipaddr = *(struct in_addr *)he->h_addr_list[0];
+ struct hostent *he;
+ if (!inet_aton(host, ipaddr)) {
+ if ((he = gethostbyname(host)) == NULL)
+ return(-1);
+ *ipaddr = *(struct in_addr *)he->h_addr_list[0];
+ }
return(0);
}
char **av = *avp;
char *p = 0, md = 0;
- if (ac && !strncmp(*av,"any",strlen(*av))) {
+ if (ac && !strncmp(*av, "any", strlen(*av))) {
ipno->s_addr = mask->s_addr = 0; av++; ac--;
} else {
p = strchr(*av, '/');
- if (!p)
+ if (!p)
p = strchr(*av, ':');
if (p) {
md = *p;
- *p++ = '\0';
+ *p++ = '\0';
}
if (lookup_host(*av, ipno) != 0)
show_usage("hostname ``%s'' unknown", *av);
switch (md) {
case ':':
- if (!inet_aton(p,mask))
+ if (!inet_aton(p, mask))
show_usage("bad netmask ``%s''", p);
break;
case '/':
}
static int
-lookup_port(const char *arg, int test, int nodash)
+lookup_port(const char *arg, int proto, int test, int nodash)
{
int val;
char *earg, buf[32];
struct servent *s;
+ char *p, *q;
snprintf(buf, sizeof(buf), "%s", arg);
- buf[strcspn(arg, nodash ? "-," : ",")] = 0;
+
+ for (p = q = buf; *p; *q++ = *p++) {
+ if (*p == '\\') {
+ if (*(p+1))
+ p++;
+ } else {
+ if (*p == ',' || (nodash && *p == '-'))
+ break;
+ }
+ }
+ *q = '\0';
+
val = (int) strtoul(buf, &earg, 0);
if (!*buf || *earg) {
+ char *protocol = NULL;
+
+ if (proto != 0) {
+ struct protoent *pe = getprotobynumber(proto);
+
+ if (pe)
+ protocol = pe->p_name;
+ }
+
setservent(1);
- if ((s = getservbyname(buf, NULL))) {
+ if ((s = getservbyname(buf, protocol))) {
val = htons(s->s_port);
} else {
if (!test) {
- errx(EX_DATAERR, "unknown port ``%s''", arg);
+ errx(EX_DATAERR, "unknown port ``%s''", buf);
}
val = -1;
}
} else {
if (val < 0 || val > 0xffff) {
if (!test) {
- errx(EX_DATAERR, "port ``%s'' out of range", arg);
+ errx(EX_DATAERR, "port ``%s'' out of range", buf);
}
val = -1;
}
return(val);
}
+/*
+ * return: 0 normally, 1 if first pair is a range,
+ * 2 if first pair is a port+mask
+ */
static int
-fill_port(cnt, ptr, off, arg)
- u_short *cnt, *ptr, off;
- char *arg;
+fill_port(u_short *cnt, u_short *ptr, u_short off, char *arg, int proto)
{
char *s;
int initial_range = 0;
- s = arg + strcspn(arg, "-,"); /* first port name can't have a dash */
+ for (s = arg; *s && *s != ',' && *s != '-' && *s != ':'; s++) {
+ if (*s == '\\' && *(s+1))
+ s++;
+ }
+ if (*s == ':') {
+ *s++ = '\0';
+ if (strchr(arg, ','))
+ errx(EX_USAGE, "port/mask must be first in list");
+ add_port(cnt, ptr, off, *arg ? lookup_port(arg, proto, 0, 0) : 0x0000);
+ arg = s;
+ s = strchr(arg,',');
+ if (s)
+ *s++ = '\0';
+ add_port(cnt, ptr, off, *arg ? lookup_port(arg, proto, 0, 0) : 0xffff);
+ arg = s;
+ initial_range = 2;
+ } else
if (*s == '-') {
*s++ = '\0';
if (strchr(arg, ','))
errx(EX_USAGE, "port range must be first in list");
- add_port(cnt, ptr, off, *arg ? lookup_port(arg, 0, 0) : 0x0000);
+ add_port(cnt, ptr, off, *arg ? lookup_port(arg, proto, 0, 0) : 0x0000);
arg = s;
s = strchr(arg,',');
if (s)
*s++ = '\0';
- add_port(cnt, ptr, off, *arg ? lookup_port(arg, 0, 0) : 0xffff);
+ add_port(cnt, ptr, off, *arg ? lookup_port(arg, proto, 0, 0) : 0xffff);
arg = s;
initial_range = 1;
}
s = strchr(arg,',');
if (s)
*s++ = '\0';
- add_port(cnt, ptr, off, lookup_port(arg, 0, 0));
+ add_port(cnt, ptr, off, lookup_port(arg, proto, 0, 0));
arg = s;
}
return initial_range;
}
static void
-fill_tcpflag(set, reset, vp)
- u_char *set, *reset;
- char **vp;
+fill_tcpflag(u_char *set, u_char *reset, char **vp)
{
char *p = *vp,*q;
u_char *d;
d = set;
}
q = strchr(p, ',');
- if (q)
+ if (q)
*q++ = '\0';
for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i)
if (!strncmp(p, flags[i].name, strlen(p))) {
}
}
+static void
+fill_tcpopts(u_char *set, u_char *reset, char **vp)
+{
+ char *p = *vp,*q;
+ u_char *d;
+
+ while (p && *p) {
+ struct tpcopts {
+ char * name;
+ u_char value;
+ } opts[] = {
+ { "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 },
+ };
+ int i;
+
+ if (*p == '!') {
+ p++;
+ d = reset;
+ } else {
+ d = set;
+ }
+ q = strchr(p, ',');
+ if (q)
+ *q++ = '\0';
+ for (i = 0; i < sizeof(opts) / sizeof(opts[0]); ++i)
+ if (!strncmp(p, opts[i].name, strlen(p))) {
+ *d |= opts[i].value;
+ break;
+ }
+ if (i == sizeof(opts) / sizeof(opts[0]))
+ show_usage("invalid tcp option ``%s''", p);
+ p = q;
+ }
+}
+
static void
fill_ipopt(u_char *set, u_char *reset, char **vp)
{
d = set;
}
q = strchr(p, ',');
- if (q)
+ if (q)
*q++ = '\0';
- if (!strncmp(p,"ssrr",strlen(p))) *d |= IP_FW_IPOPT_SSRR;
- if (!strncmp(p,"lsrr",strlen(p))) *d |= IP_FW_IPOPT_LSRR;
- if (!strncmp(p,"rr",strlen(p))) *d |= IP_FW_IPOPT_RR;
- if (!strncmp(p,"ts",strlen(p))) *d |= IP_FW_IPOPT_TS;
+ if (!strncmp(p, "ssrr", strlen(p))) *d |= IP_FW_IPOPT_SSRR;
+ if (!strncmp(p, "lsrr", strlen(p))) *d |= IP_FW_IPOPT_LSRR;
+ if (!strncmp(p, "rr", strlen(p))) *d |= IP_FW_IPOPT_RR;
+ if (!strncmp(p, "ts", strlen(p))) *d |= IP_FW_IPOPT_TS;
p = q;
}
}
{
unsigned long icmptype;
- if ( *c == ',' )
+ if (*c == ',')
++c;
icmptype = strtoul(c, &c, 0);
- if ( *c != ',' && *c != '\0' )
+ if (*c != ',' && *c != '\0')
show_usage("invalid ICMP type");
if (icmptype >= IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8)
show_usage("ICMP type out of range");
- types[icmptype / (sizeof(unsigned) * 8)] |=
+ types[icmptype / (sizeof(unsigned) * 8)] |=
1 << (icmptype % (sizeof(unsigned) * 8));
*fw_flg |= IP_FW_F_ICMPBIT;
}
}
static void
-delete(ac,av)
+delete(ac, av)
int ac;
char **av;
{
struct ip_fw rule;
+ #ifdef DUMMYNET
struct dn_pipe pipe;
+ #endif /* DUMMYNET */
int i;
int exitval = EX_OK;
memset(&rule, 0, sizeof rule);
+ #ifdef DUMMYNET
memset(&pipe, 0, sizeof pipe);
+ #endif /* DUMMYNET */
+ rule.version = IP_FW_CURRENT_API_VERSION;
av++; ac--;
/* Rule number */
- while (ac && isdigit(**av)) {
- if (do_pipe) {
- pipe.pipe_nr = atoi(*av); av++; ac--;
- i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_DEL,
- &pipe, sizeof pipe);
- if (i) {
- exitval = 1;
- warn("rule %u: setsockopt(%s)", pipe.pipe_nr, "IP_DUMMYNET_DEL");
- }
- } else {
- rule.fw_number = atoi(*av); av++; ac--;
- i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule);
- if (i) {
- exitval = EX_UNAVAILABLE;
- warn("rule %u: setsockopt(%s)", rule.fw_number, "IP_FW_DEL");
+ while (ac && isdigit(**av))
+ {
+ i = atoi(*av); av++; ac--;
+
+ #ifdef DUMMYNET
+ if (do_pipe)
+ {
+ if (do_pipe == 1) pipe.pipe_nr = i;
+ else pipe.fs.fs_nr = i;
+
+ i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_DEL, &pipe, sizeof pipe);
+ if (i)
+ {
+ exitval = 1;
+ warn("rule %u: setsockopt(%s)", do_pipe == 1 ? pipe.pipe_nr : pipe.fs.fs_nr,
+ "IP_DUMMYNET_DEL");
+ }
+ }
+ else
+ #endif /* DUMMYNET */
+ {
+ rule.fw_number = i;
+ i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule);
+ if (i)
+ {
+ exitval = EX_UNAVAILABLE;
+ warn("rule %u: setsockopt(%s)", rule.fw_number, "IP_FW_DEL");
+ }
}
}
- }
+
if (exitval != EX_OK)
exit(exitval);
}
* If a unit was specified, check for that exact interface.
* If a wildcard was specified, check for unit 0.
*/
- snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
+ snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
ifu->fu_via_if.name,
ifu->fu_via_if.unit == -1 ? 0 : ifu->fu_via_if.unit);
*byname = 0;
}
+#ifdef DUMMYNET
static void
config_pipe(int ac, char **av)
{
struct dn_pipe pipe;
- int i ;
- char *end ;
-
+ int i;
+ char *end;
+
memset(&pipe, 0, sizeof pipe);
-
+
av++; ac--;
/* Pipe number */
if (ac && isdigit(**av)) {
- pipe.pipe_nr = atoi(*av); av++; ac--;
+ 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,"bw",strlen(*av)) ||
- ! strncmp(*av,"bandwidth",strlen(*av))) {
- pipe.bandwidth = strtoul(av[1], &end, 0);
- if (*end == 'K')
- end++, pipe.bandwidth *= 1000 ;
- else if (*end == 'M')
- end++, pipe.bandwidth *= 1000000 ;
- if (*end == 'B')
- pipe.bandwidth *= 8 ;
- av+=2; ac-=2;
- } else if (!strncmp(*av,"delay",strlen(*av)) ) {
- pipe.delay = strtoul(av[1], NULL, 0);
- av+=2; ac-=2;
- } else if (!strncmp(*av,"plr",strlen(*av)) ) {
-
+ if (!strncmp(*av, "plr", strlen(*av))) {
+
double d = strtod(av[1], NULL);
- pipe.plr = (int)(d*0x7fffffff) ;
+ 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.queue_size = strtoul(av[1], &end, 0);
- if (*end == 'K') {
- pipe.queue_size_bytes = pipe.queue_size*1024 ;
- pipe.queue_size = 0 ;
- } else if (*end == 'B') {
- pipe.queue_size_bytes = pipe.queue_size ;
- pipe.queue_size = 0 ;
+ } 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;
}
av+=2; ac-=2;
+ } else if (!strncmp(*av, "buckets", strlen(*av))) {
+ pipe.fs.rq_size = strtoul(av[1], NULL, 0);
+ av+=2; ac-=2;
+ } 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;
+ u_int32_t *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--;
+ } else {
+ for (;;) {
+ if (ac < 1)
+ break;
+ if (!strncmp(*av, "dst-ip", strlen(*av)))
+ par = &(pipe.fs.flow_mask.dst_ip);
+ else if (!strncmp(*av, "src-ip", strlen(*av)))
+ par = &(pipe.fs.flow_mask.src_ip);
+ else if (!strncmp(*av, "dst-port", strlen(*av)))
+ (u_int16_t *)par = &(pipe.fs.flow_mask.dst_port);
+ else if (!strncmp(*av, "src-port", strlen(*av)))
+ (u_int16_t *)par = &(pipe.fs.flow_mask.src_port);
+ else if (!strncmp(*av, "proto", strlen(*av)))
+ (u_int8_t *)par = &(pipe.fs.flow_mask.proto);
+ else
+ break;
+ if (ac < 2)
+ show_usage("mask: %s value missing", *av);
+ if (*av[1] == '/') {
+ a = strtoul(av[1]+1, &end, 0);
+ if (a == 32) /* special case... */
+ a = ~0;
+ else
+ a = (1 << a) - 1;
+ fprintf(stderr, " mask is 0x%08x\n", a);
+ } else
+ a = strtoul(av[1], &end, 0);
+ if ((u_int16_t *)par == &(pipe.fs.flow_mask.src_port) ||
+ (u_int16_t *)par == &(pipe.fs.flow_mask.dst_port)) {
+ if (a >= (1<<16))
+ show_usage("mask: %s must be 16 bit, not 0x%08x",
+ *av, a);
+ *((u_int16_t *)par) = (u_int16_t) a;
+ } else if ((u_int8_t *)par == &(pipe.fs.flow_mask.proto)) {
+ if (a >= (1<<8))
+ show_usage("mask: %s must be 8 bit, not 0x%08x",
+ *av, a);
+ *((u_int8_t *)par) = (u_int8_t) a;
+ } else
+ *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)
+ show_usage("w_q %f must be 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)
+ show_usage("max_p %f must be 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 {
+ if (do_pipe == 1) {
+ /* some commands are only good for pipes. */
+ if (!strncmp(*av, "bw", strlen(*av)) ||
+ ! strncmp(*av, "bandwidth", strlen(*av))) {
+ 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;
+ }
+ av+=2; ac-=2;
+ } else if (!strncmp(*av, "delay", strlen(*av))) {
+ pipe.delay = strtoul(av[1], NULL, 0);
+ av+=2; ac-=2;
+ } else
+ show_usage("unrecognised pipe option ``%s''", *av);
+ } else { /* this refers to a queue */
+ if (!strncmp(*av, "weight", strlen(*av))) {
+ pipe.fs.weight = strtoul(av[1], &end, 0);
+ av += 2;
+ ac -= 2;
+ } else if (!strncmp(*av, "pipe", strlen(*av))) {
+ pipe.fs.parent_nr = strtoul(av[1], &end, 0);
+ av += 2;
+ ac -= 2;
} else
show_usage("unrecognised option ``%s''", *av);
}
- if (pipe.pipe_nr == 0 )
- show_usage("pipe_nr %d be > 0", pipe.pipe_nr);
- if (pipe.queue_size > 100 )
- show_usage("queue size %d must be 2 <= x <= 100", pipe.queue_size);
- if (pipe.delay > 10000 )
+ }
+ }
+ if (do_pipe == 1) {
+ if (pipe.pipe_nr == 0)
+ show_usage("pipe_nr %d must be > 0", pipe.pipe_nr);
+ if (pipe.delay > 10000)
show_usage("delay %d must be < 10000", pipe.delay);
+ } else { /* do_pipe == 2, queue */
+ if (pipe.fs.parent_nr == 0)
+ show_usage("pipe %d must be > 0", pipe.fs.parent_nr);
+ if (pipe.fs.weight >100)
+ show_usage("weight %d must be <= 100", pipe.fs.weight);
+ }
+ if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) {
+ if (pipe.fs.qsize > 1024*1024)
+ show_usage("queue size %d, must be < 1MB",
+ pipe.fs.qsize);
+ } else {
+ if (pipe.fs.qsize > 100)
+ show_usage("queue size %d, must be 2 <= x <= 100",
+ pipe.fs.qsize);
+ }
+ if (pipe.fs.flags_fs & DN_IS_RED) {
+ if (pipe.fs.min_th >= pipe.fs.max_th)
+ show_usage("min_th %d must be < than max_th %d",
+ pipe.fs.min_th, pipe.fs.max_th);
+ if (pipe.fs.max_th == 0)
+ show_usage("max_th must be > 0");
+ if (pipe.bandwidth) {
+ size_t len;
+ int lookup_depth, avg_pkt_size;
+ double s, idle, weight, w_q;
+ struct clockinfo clock;
+ int t;
+
+ len = sizeof(int);
+ if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
+ &lookup_depth, &len, NULL, 0) == -1)
+
+ errx(1, "sysctlbyname(\"%s\")",
+ "net.inet.ip.dummynet.red_lookup_depth");
+ if (lookup_depth == 0)
+ show_usage("net.inet.ip.dummynet.red_lookup_depth must"
+ "greater than zero");
+
+ len = sizeof(int);
+ if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
+ &avg_pkt_size, &len, NULL, 0) == -1)
+
+ errx(1, "sysctlbyname(\"%s\")",
+ "net.inet.ip.dummynet.red_avg_pkt_size");
+ if (avg_pkt_size == 0)
+ show_usage("net.inet.ip.dummynet.red_avg_pkt_size must"
+ "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 */
+ s = clock.hz * avg_pkt_size * 8 / pipe.bandwidth;
+
+ /*
+ * 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));
+ }
+ }
#if 0
printf("configuring pipe %d bw %d delay %d size %d\n",
pipe.pipe_nr, pipe.bandwidth, pipe.delay, pipe.queue_size);
#endif
- i = setsockopt(s,IPPROTO_IP, IP_DUMMYNET_CONFIGURE, &pipe,sizeof pipe);
+ i = setsockopt(s,IPPROTO_IP, IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe);
if (i)
err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
-
+
}
+#endif /* DUMMYNET */
static void
-add(ac,av)
+add(ac, av)
int ac;
char **av;
{
u_char proto;
struct protoent *pe;
int saw_xmrc = 0, saw_via = 0;
-
+
memset(&rule, 0, sizeof rule);
+ rule.version = IP_FW_CURRENT_API_VERSION;
av++; ac--;
}
/* Action */
+ if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) {
+ double d = strtod(av[1], NULL);
+ if (d <= 0 || d > 1)
+ show_usage("illegal match prob. %s", av[1]);
+ if (d != 1) { /* 1 means always match */
+ rule.fw_flg |= IP_FW_F_RND_MATCH;
+ /* we really store dont_match probability */
+ (long)rule.pipe_ptr = (long)((1 - d) * 0x7fffffff);
+ }
+ av += 2; ac -= 2;
+ }
+
if (ac == 0)
show_usage("missing action");
- if (!strncmp(*av,"accept",strlen(*av))
- || !strncmp(*av,"pass",strlen(*av))
- || !strncmp(*av,"allow",strlen(*av))
- || !strncmp(*av,"permit",strlen(*av))) {
+ if (!strncmp(*av, "accept", strlen(*av))
+ || !strncmp(*av, "pass" ,strlen(*av))
+ || !strncmp(*av, "allow", strlen(*av))
+ || !strncmp(*av, "permit", strlen(*av))) {
rule.fw_flg |= IP_FW_F_ACCEPT; av++; ac--;
- } else if (!strncmp(*av,"count",strlen(*av))) {
+ } else if (!strncmp(*av, "count", strlen(*av))) {
rule.fw_flg |= IP_FW_F_COUNT; av++; ac--;
- } else if (!strncmp(*av,"pipe",strlen(*av))) {
+ }
+ #ifdef DUMMYNET
+ else if (!strncmp(*av, "pipe", strlen(*av))) {
rule.fw_flg |= IP_FW_F_PIPE; av++; ac--;
if (!ac)
show_usage("missing pipe number");
rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
- } else if (!strncmp(*av,"divert",strlen(*av))) {
+ } else if (!strncmp(*av, "queue", strlen(*av))) {
+ rule.fw_flg |= IP_FW_F_QUEUE; av++; ac--;
+ if (!ac)
+ show_usage("missing queue number");
+ rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
+ }
+ #endif /* DUMMYNET */
+ else if (!strncmp(*av, "divert", strlen(*av))) {
rule.fw_flg |= IP_FW_F_DIVERT; av++; ac--;
if (!ac)
show_usage("missing %s port", "divert");
else
show_usage("illegal %s port", "divert");
}
- } else if (!strncmp(*av,"tee",strlen(*av))) {
+ } else if (!strncmp(*av, "tee", strlen(*av))) {
rule.fw_flg |= IP_FW_F_TEE; av++; ac--;
if (!ac)
show_usage("missing %s port", "tee divert");
else
show_usage("illegal %s port", "tee divert");
}
-#ifndef IPFW_TEE_IS_FINALLY_IMPLEMENTED
- err(EX_USAGE, "the ``tee'' action is not implemented");
-#endif
- } else if (!strncmp(*av,"fwd",strlen(*av)) ||
- !strncmp(*av,"forward",strlen(*av))) {
+ } else if (!strncmp(*av, "fwd", strlen(*av)) ||
+ !strncmp(*av, "forward", strlen(*av))) {
struct in_addr dummyip;
char *pp;
rule.fw_flg |= IP_FW_F_FWD; av++; ac--;
if(pp != NULL)
{
*(pp++) = '\0';
- rule.fw_fwd_ip.sin_port = lookup_port(pp, 1, 1);
- if(rule.fw_fwd_ip.sin_port == (unsigned int)-1)
- show_usage("illegal forwarding port");
+ i = lookup_port(pp, 0, 1, 0);
+ if (i == -1)
+ show_usage("illegal forwarding port ``%s''", pp);
+ else
+ rule.fw_fwd_ip.sin_port = (u_short)i;
}
fill_ip(&(rule.fw_fwd_ip.sin_addr), &dummyip, &ac, &av);
if (rule.fw_fwd_ip.sin_addr.s_addr == 0)
show_usage("illegal forwarding IP address");
- } else if (!strncmp(*av,"skipto",strlen(*av))) {
+ } else if (!strncmp(*av, "skipto", strlen(*av))) {
rule.fw_flg |= IP_FW_F_SKIPTO; av++; ac--;
if (!ac)
show_usage("missing skipto rule number");
rule.fw_skipto_rule = strtoul(*av, NULL, 0); av++; ac--;
- } else if ((!strncmp(*av,"deny",strlen(*av))
- || !strncmp(*av,"drop",strlen(*av)))) {
+ } else if ((!strncmp(*av, "deny", strlen(*av))
+ || !strncmp(*av, "drop", strlen(*av)))) {
rule.fw_flg |= IP_FW_F_DENY; av++; ac--;
- } else if (!strncmp(*av,"reject",strlen(*av))) {
+ } else if (!strncmp(*av, "reject", strlen(*av))) {
rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
rule.fw_reject_code = ICMP_UNREACH_HOST;
- } else if (!strncmp(*av,"reset",strlen(*av))) {
+ } else if (!strncmp(*av, "reset", strlen(*av))) {
rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
rule.fw_reject_code = IP_FW_REJECT_RST; /* check TCP later */
- } else if (!strncmp(*av,"unreach",strlen(*av))) {
+ } else if (!strncmp(*av, "unreach", strlen(*av))) {
rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
fill_reject_code(&rule.fw_reject_code, *av); av++; ac--;
+ } else if (!strncmp(*av, "check-state", strlen(*av))) {
+ rule.fw_flg |= IP_FW_F_CHECK_S; av++; ac--;
+ goto done;
} else {
show_usage("invalid action ``%s''", *av);
}
/* [log] */
- if (ac && !strncmp(*av,"log",strlen(*av))) {
+ if (ac && !strncmp(*av, "log", strlen(*av))) {
rule.fw_flg |= IP_FW_F_PRN; av++; ac--;
}
+ if (ac && !strncmp(*av, "logamount", strlen(*av))) {
+ if (!(rule.fw_flg & IP_FW_F_PRN))
+ show_usage("``logamount'' not valid without ``log''");
+ ac--; av++;
+ if (!ac)
+ show_usage("``logamount'' requires argument");
+ rule.fw_logamount = atoi(*av);
+ if (rule.fw_logamount < 0)
+ show_usage("``logamount'' argument must be positive");
+ if (rule.fw_logamount == 0)
+ rule.fw_logamount = -1;
+ ac--; av++;
+ }
/* protocol */
if (ac == 0)
show_usage("missing protocol");
if ((proto = atoi(*av)) > 0) {
rule.fw_prot = proto; av++; ac--;
- } else if (!strncmp(*av,"all",strlen(*av))) {
+ } else if (!strncmp(*av, "all", strlen(*av))) {
rule.fw_prot = IPPROTO_IP; av++; ac--;
} else if ((pe = getprotobyname(*av)) != NULL) {
rule.fw_prot = pe->p_proto; av++; ac--;
show_usage("``reset'' is only valid for tcp packets");
/* from */
- if (ac && !strncmp(*av,"from",strlen(*av))) { av++; ac--; }
+ if (ac && !strncmp(*av, "from", strlen(*av))) { av++; ac--; }
else
show_usage("missing ``from''");
- if (ac && !strncmp(*av,"not",strlen(*av))) {
+ if (ac && !strncmp(*av, "not", strlen(*av))) {
rule.fw_flg |= IP_FW_F_INVSRC;
av++; ac--;
}
if (!ac)
show_usage("missing arguments");
- fill_ip(&rule.fw_src, &rule.fw_smsk, &ac, &av);
+ if (ac && !strncmp(*av, "me", strlen(*av))) {
+ rule.fw_flg |= IP_FW_F_SME;
+ av++; ac--;
+ } else {
+ fill_ip(&rule.fw_src, &rule.fw_smsk, &ac, &av);
+ }
- if (ac && (isdigit(**av) || lookup_port(*av, 1, 1) >= 0)) {
+ if (ac && (isdigit(**av) || lookup_port(*av, rule.fw_prot, 1, 1) >= 0)) {
u_short nports = 0;
+ int retval;
- if (fill_port(&nports, rule.fw_uar.fw_pts, 0, *av))
+ retval = fill_port(&nports, rule.fw_uar.fw_pts, 0, *av, rule.fw_prot);
+ if (retval == 1)
rule.fw_flg |= IP_FW_F_SRNG;
+ else if (retval == 2)
+ rule.fw_flg |= IP_FW_F_SMSK;
IP_FW_SETNSRCP(&rule, nports);
av++; ac--;
}
/* to */
- if (ac && !strncmp(*av,"to",strlen(*av))) { av++; ac--; }
+ if (ac && !strncmp(*av, "to", strlen(*av))) { av++; ac--; }
else
show_usage("missing ``to''");
- if (ac && !strncmp(*av,"not",strlen(*av))) {
+ if (ac && !strncmp(*av, "not", strlen(*av))) {
rule.fw_flg |= IP_FW_F_INVDST;
av++; ac--;
}
if (!ac)
show_usage("missing arguments");
- fill_ip(&rule.fw_dst, &rule.fw_dmsk, &ac, &av);
+ if (ac && !strncmp(*av, "me", strlen(*av))) {
+ rule.fw_flg |= IP_FW_F_DME;
+ av++; ac--;
+ } else {
+ fill_ip(&rule.fw_dst, &rule.fw_dmsk, &ac, &av);
+ }
- if (ac && (isdigit(**av) || lookup_port(*av, 1, 1) >= 0)) {
+ if (ac && (isdigit(**av) || lookup_port(*av, rule.fw_prot, 1, 1) >= 0)) {
u_short nports = 0;
+ int retval;
- if (fill_port(&nports,
- rule.fw_uar.fw_pts, IP_FW_GETNSRCP(&rule), *av))
+ retval = fill_port(&nports,
+ rule.fw_uar.fw_pts, IP_FW_GETNSRCP(&rule), *av, rule.fw_prot);
+ if (retval == 1)
rule.fw_flg |= IP_FW_F_DRNG;
+ else if (retval == 2)
+ rule.fw_flg |= IP_FW_F_DMSK;
IP_FW_SETNDSTP(&rule, nports);
av++; ac--;
}
}
while (ac) {
- if (!strncmp(*av,"in",strlen(*av))) {
+ if (!strncmp(*av, "uid", strlen(*av))) {
+ struct passwd *pwd;
+ char *end;
+ uid_t uid;
+
+ rule.fw_flg |= IP_FW_F_UID;
+ ac--; av++;
+ if (!ac)
+ show_usage("``uid'' requires argument");
+
+ uid = strtoul(*av, &end, 0);
+ if (*end == '\0')
+ pwd = getpwuid(uid);
+ else
+ pwd = getpwnam(*av);
+ if (pwd == NULL)
+ show_usage("uid \"%s\" is nonexistant", *av);
+ rule.fw_uid = pwd->pw_uid;
+ ac--; av++;
+ continue;
+ }
+ if (!strncmp(*av, "in", strlen(*av))) {
rule.fw_flg |= IP_FW_F_IN;
av++; ac--; continue;
}
- if (!strncmp(*av,"out",strlen(*av))) {
+ 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) {
+ (int)rule.next_rule_ptr = type;
+ av++; ac--;
+ }
+ continue;
+ }
+ if (!strncmp(*av, "bridged", strlen(*av))) {
+ rule.fw_flg |= IP_FW_BRIDGED;
+ av++; ac--; continue;
+ }
+ if (!strncmp(*av, "out", strlen(*av))) {
rule.fw_flg |= IP_FW_F_OUT;
av++; ac--; continue;
}
- if (ac && !strncmp(*av,"xmit",strlen(*av))) {
+ if (ac && !strncmp(*av, "xmit", strlen(*av))) {
union ip_fw_if ifu;
int byname;
" with ``xmit'' and ``recv''");
}
saw_xmrc = 1;
- av++; ac--;
+ av++; ac--;
fill_iface("xmit", &ifu, &byname, ac, *av);
rule.fw_out_if = ifu;
rule.fw_flg |= IP_FW_F_OIFACE;
rule.fw_flg |= IP_FW_F_OIFNAME;
av++; ac--; continue;
}
- if (ac && !strncmp(*av,"recv",strlen(*av))) {
+ if (ac && !strncmp(*av, "recv", strlen(*av))) {
union ip_fw_if ifu;
int byname;
if (saw_via)
goto badviacombo;
saw_xmrc = 1;
- av++; ac--;
+ av++; ac--;
fill_iface("recv", &ifu, &byname, ac, *av);
rule.fw_in_if = ifu;
rule.fw_flg |= IP_FW_F_IIFACE;
rule.fw_flg |= IP_FW_F_IIFNAME;
av++; ac--; continue;
}
- if (ac && !strncmp(*av,"via",strlen(*av))) {
+ if (ac && !strncmp(*av, "via", strlen(*av))) {
union ip_fw_if ifu;
int byname = 0;
if (saw_xmrc)
goto badviacombo;
saw_via = 1;
- av++; ac--;
+ av++; ac--;
fill_iface("via", &ifu, &byname, ac, *av);
rule.fw_out_if = rule.fw_in_if = ifu;
if (byname)
(IP_FW_F_IIFNAME | IP_FW_F_OIFNAME);
av++; ac--; continue;
}
- if (!strncmp(*av,"fragment",strlen(*av))) {
+ if (!strncmp(*av, "fragment", strlen(*av))) {
rule.fw_flg |= IP_FW_F_FRAG;
av++; ac--; continue;
}
- if (!strncmp(*av,"ipoptions",strlen(*av))) {
- av++; ac--;
+ if (!strncmp(*av, "ipoptions", strlen(*av))) {
+ av++; ac--;
if (!ac)
show_usage("missing argument"
" for ``ipoptions''");
av++; ac--; continue;
}
if (rule.fw_prot == IPPROTO_TCP) {
- if (!strncmp(*av,"established",strlen(*av))) {
- rule.fw_tcpf |= IP_FW_TCPF_ESTAB;
+ if (!strncmp(*av, "established", strlen(*av))) {
+ rule.fw_ipflg |= IP_FW_IF_TCPEST;
av++; ac--; continue;
}
- if (!strncmp(*av,"setup",strlen(*av))) {
+ if (!strncmp(*av, "setup", strlen(*av))) {
rule.fw_tcpf |= IP_FW_TCPF_SYN;
rule.fw_tcpnf |= IP_FW_TCPF_ACK;
av++; ac--; continue;
}
- if (!strncmp(*av,"tcpflags",strlen(*av))) {
- av++; ac--;
+ if (!strncmp(*av, "tcpflags", strlen(*av)) ||
+ !strncmp(*av, "tcpflgs", strlen(*av))) {
+ av++; ac--;
if (!ac)
show_usage("missing argument"
" for ``tcpflags''");
fill_tcpflag(&rule.fw_tcpf, &rule.fw_tcpnf, av);
av++; ac--; continue;
}
+ if (!strncmp(*av, "tcpoptions", strlen(*av)) ||
+ !strncmp(*av, "tcpopts", strlen(*av))) {
+ av++; ac--;
+ if (!ac)
+ show_usage("missing argument"
+ " for ``tcpoptions''");
+ fill_tcpopts(&rule.fw_tcpopt, &rule.fw_tcpnopt, av);
+ av++; ac--; continue;
+ }
}
if (rule.fw_prot == IPPROTO_ICMP) {
- if (!strncmp(*av,"icmptypes",strlen(*av))) {
+ if (!strncmp(*av, "icmptypes", strlen(*av))) {
av++; ac--;
if (!ac)
show_usage("missing argument"
if (rule.fw_nports)
show_usage("can't mix 'frag' and port specifications");
}
-
+ 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");
+ } else if (rule.fw_logamount == -1)
+ rule.fw_logamount = 0;
+ rule.fw_loghighest = rule.fw_logamount;
+ }
+done:
+ i = sizeof(rule);
+ if (getsockopt(s, IPPROTO_IP, IP_FW_ADD, &rule, &i) == -1)
+ err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
if (!do_quiet)
show_ipfw(&rule, 10, 10);
- i = setsockopt(s, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
- if (i)
- err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_ADD");
}
static void
int ac;
char **av;
{
+ struct ip_fw rule;
+ memset(&rule, 0, sizeof rule);
+ rule.version = IP_FW_CURRENT_API_VERSION;
+
av++; ac--;
if (!ac) {
/* clear all entries */
- if (setsockopt(s,IPPROTO_IP,IP_FW_ZERO,NULL,0)<0)
+ if (setsockopt(s, IPPROTO_IP, IP_FW_ZERO, &rule, sizeof rule) < 0)
err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_ZERO");
if (!do_quiet)
printf("Accounting cleared.\n");
} else {
- struct ip_fw rule;
int failed = EX_OK;
- memset(&rule, 0, sizeof rule);
while (ac) {
/* Rule number */
if (isdigit(**av)) {
}
}
+static void
+resetlog (ac, av)
+ int ac;
+ char **av;
+{
+ struct ip_fw rule;
+ memset(&rule, 0, sizeof rule);
+ rule.version = IP_FW_CURRENT_API_VERSION;
+
+ av++; ac--;
+
+ if (!ac) {
+ /* clear all entries */
+ if (setsockopt(s, IPPROTO_IP, IP_FW_RESETLOG, &rule, sizeof rule) < 0)
+ err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_RESETLOG");
+ if (!do_quiet)
+ printf("Logging counts reset.\n");
+ } else {
+ int failed = EX_OK;
+
+ 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(%s)", rule.fw_number,
+ "IP_FW_RESETLOG");
+ failed = EX_UNAVAILABLE;
+ }
+ else if (!do_quiet)
+ printf("Entry %d logging count reset\n",
+ rule.fw_number);
+ } else
+ show_usage("invalid rule number ``%s''", *av);
+ }
+ if (failed != EX_OK)
+ exit(failed);
+ }
+}
+
static int
-ipfw_main(ac,av)
+ipfw_main(ac, av)
int ac;
char **av;
{
int ch;
- extern int optreset; /* XXX should be declared in <unistd.h> */
- if ( ac == 1 ) {
+ if (ac == 1) {
show_usage(NULL);
}
do_force = !isatty(STDIN_FILENO);
optind = optreset = 1;
- while ((ch = getopt(ac, av, "afqtN")) != -1)
+ while ((ch = getopt(ac, av, "s:afqtvN")) != -1)
switch(ch) {
+ case 's': /* sort */
+ do_sort= atoi(optarg);
+ break;
case 'a':
- do_acct=1;
+ do_acct = 1;
break;
case 'f':
- do_force=1;
+ do_force = 1;
break;
case 'q':
- do_quiet=1;
+ do_quiet = 1;
break;
case 't':
- do_time=1;
+ do_time = 1;
+ break;
+ case 'v': /* verbose */
+ verbose++;
break;
case 'N':
- do_resolv=1;
+ do_resolv = 1;
break;
default:
show_usage(NULL);
ac -= optind;
if (*(av+=optind)==NULL) {
- show_usage("Bad arguments");
+ show_usage("bad arguments");
}
- if (!strncmp(*av, "pipe", strlen(*av))) {
- do_pipe = 1 ;
- ac-- ;
- av++ ;
- }
+ #ifdef DUMMYNET
+ 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) {
show_usage("pipe requires arguments");
}
- /* allow argument swapping */
- if (ac > 1 && *av[0]>='0' && *av[0]<='9') {
- char *p = av[0] ;
- av[0] = av[1] ;
- av[1] = p ;
- }
+ #endif /* DUMMYNET */
+
+ /* allow argument swapping */
+ if (ac > 1 && *av[0] >= '0' && *av[0] <= '9') {
+ char *p = av[0];
+ av[0] = av[1];
+ av[1] = p;
+ }
if (!strncmp(*av, "add", strlen(*av))) {
- add(ac,av);
- } else if (do_pipe && !strncmp(*av, "config", strlen(*av))) {
- config_pipe(ac,av);
- } else if (!strncmp(*av, "delete", strlen(*av))) {
- delete(ac,av);
+ add(ac, av);
+ }
+ #ifdef DUMMYNET
+ else if (do_pipe && !strncmp(*av, "config", strlen(*av))) {
+ config_pipe(ac, av);
+ }
+ #endif /* DUMMYNET */
+ else if (!strncmp(*av, "delete", strlen(*av))) {
+ delete(ac, av);
} else if (!strncmp(*av, "flush", strlen(*av))) {
int do_flush = 0;
- if ( do_force || do_quiet )
+ if (do_force || do_quiet)
do_flush = 1;
else {
int c;
/* Ask the user */
printf("Are you sure? [yn] ");
+ fflush(stdout);
do {
- fflush(stdout);
c = toupper(getc(stdin));
while (c != '\n' && getc(stdin) != '\n')
if (feof(stdin))
return (0);
} while (c != 'Y' && c != 'N');
printf("\n");
- if (c == 'Y')
+ if (c == 'Y')
do_flush = 1;
}
- if ( do_flush ) {
- if (setsockopt(s,IPPROTO_IP,IP_FW_FLUSH,NULL,0) < 0)
- err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_FLUSH");
+ if (do_flush) {
+ int error = 0;
+
+ #ifdef DUMMYNET
+ if (do_pipe)
+ {
+ error = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_FLUSH, NULL, 0);
+ }
+ else
+ #endif /* DUMMYNET */
+ {
+ struct ip_fw rule;
+ memset(&rule, 0, sizeof rule);
+ rule.version = IP_FW_CURRENT_API_VERSION;
+ error = setsockopt(s, IPPROTO_IP, IP_FW_FLUSH, &rule, sizeof rule);
+ }
+
+ if (error < 0)
+ #ifdef DUMMYNET
+ err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)",
+ do_pipe ? "DUMMYNET" : "FW");
+ #else /* DUMMYNET */
+ err(EX_UNAVAILABLE, "setsockopt(IP_FW_FLUSH)");
+ #endif /* DUMMYNET */
if (!do_quiet)
+ #ifdef DUMMYNET
+ printf("Flushed all %s.\n",
+ do_pipe ? "pipes" : "rules");
+ #else /* DUMMYNET */
printf("Flushed all rules.\n");
+ #endif /* DUMMYNET */
}
} else if (!strncmp(*av, "zero", strlen(*av))) {
- zero(ac,av);
+ zero(ac, av);
+ } else if (!strncmp(*av, "resetlog", strlen(*av))) {
+ resetlog(ac, av);
} else if (!strncmp(*av, "print", strlen(*av))) {
- list(--ac,++av);
+ list(--ac, ++av);
} else if (!strncmp(*av, "list", strlen(*av))) {
- list(--ac,++av);
+ list(--ac, ++av);
} else if (!strncmp(*av, "show", strlen(*av))) {
do_acct++;
- list(--ac,++av);
+ list(--ac, ++av);
} else {
- show_usage("Bad arguments");
+ show_usage("bad arguments");
}
return 0;
}
-int
+int
main(ac, av)
int ac;
char **av;
char buf[BUFSIZ];
char *a, *p, *args[MAX_ARGS], *cmd = NULL;
char linename[10];
- int i, c, qflag, pflag, status;
+ int i, c, lineno, qflag, pflag, status;
FILE *f = NULL;
pid_t preproc = 0;
- s = socket( AF_INET, SOCK_RAW, IPPROTO_RAW );
- if ( s < 0 )
+ s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ if (s < 0)
err(EX_UNAVAILABLE, "socket");
- setbuf(stdout,0);
+ setbuf(stdout, 0);
- if (ac > 1 && access(av[ac - 1], R_OK) == 0) {
+ /*
+ * this is a nasty check on the last argument!!!
+ * If there happens to be a filename matching a keyword in the current
+ * directory, things will fail miserably.
+ */
+
+ if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) {
qflag = pflag = i = 0;
lineno = 0;
case 0:
/* child */
- if (dup2(fileno(f), 0) == -1 ||
- dup2(pipedes[1], 1) == -1)
+ if (dup2(fileno(f), 0) == -1
+ || dup2(pipedes[1], 1) == -1)
err(EX_OSERR, "dup2()");
fclose(f);
close(pipedes[1]);
continue;
if ((p = strchr(buf, '#')) != NULL)
*p = '\0';
- i=1;
- if (qflag) args[i++]="-q";
+ 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);
+ errx(EX_USAGE, "%s: too many arguments",
+ linename);
args[i] = NULL;
- ipfw_main(i, args);
+ ipfw_main(i, args);
}
fclose(f);
if (pflag) {
- if (waitpid(preproc, &status, 0) != -1) {
- if (WIFEXITED(status)) {
- if (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));
- }
- }
+ 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));
}
-
- } else
- ipfw_main(ac,av);
+ } else {
+ ipfw_main(ac, av);
+ }
return EX_OK;
}