summaryrefslogtreecommitdiffstats
path: root/sbin/ipfw/ipfw.c
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>1997-06-02 05:02:37 +0000
committerjulian <julian@FreeBSD.org>1997-06-02 05:02:37 +0000
commit18750f03542b6c804f678f3b4fc1d4b4405fa79a (patch)
tree3a450132fdb541b607910a830c480304a9099681 /sbin/ipfw/ipfw.c
parentff62a150f76ce0a4c48dd9db8488b95c2fb31db5 (diff)
downloadFreeBSD-src-18750f03542b6c804f678f3b4fc1d4b4405fa79a.zip
FreeBSD-src-18750f03542b6c804f678f3b4fc1d4b4405fa79a.tar.gz
Submitted by: Whistle Communications (archie Cobbs)
these are quite extensive additions to the ipfw code. they include a change to the API because the old method was broken, but the user view is kept the same. The new code allows a particular match to skip forward to a particular line number, so that blocks of rules can be used without checking all the intervening rules. There are also many more ways of rejecting connections especially TCP related, and many many more ... see the man page for a complete description.
Diffstat (limited to 'sbin/ipfw/ipfw.c')
-rw-r--r--sbin/ipfw/ipfw.c622
1 files changed, 405 insertions, 217 deletions
diff --git a/sbin/ipfw/ipfw.c b/sbin/ipfw/ipfw.c
index 1254721..7a426ec 100644
--- a/sbin/ipfw/ipfw.c
+++ b/sbin/ipfw/ipfw.c
@@ -16,7 +16,7 @@
*
* NEW command line interface for IP firewall facility
*
- * $Id: ipfw.c,v 1.41 1997/03/05 12:08:44 bde Exp $
+ * $Id: ipfw.c,v 1.42 1997/03/29 03:32:28 imp Exp $
*
*/
@@ -32,18 +32,23 @@
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <unistd.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 <netinet/tcp.h>
#include <arpa/inet.h>
-int lineno = -1;
-char progname[BUFSIZ]; /* Program name for errors */
+extern char *__progname;
+int lineno = -1;
int s; /* main RAW socket */
int do_resolv=0; /* Would try to resolv all */
@@ -52,9 +57,33 @@ 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
-mask_bits(m_ad)
- struct in_addr m_ad;
+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" },
+ { 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;
u_long mask;
@@ -101,15 +130,47 @@ print_port(prot, port, comma)
printf("%s%d",comma,port);
}
-void
-show_ipfw(chain)
- struct ip_fw *chain;
+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);
+ ifnb[FW_IFNLEN]='\0';
+ if (un->fu_via_if.unit == -1)
+ printf(" %s %s*", key, ifnb);
+ 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));
+ } 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);
+}
+
+static void
+show_ipfw(struct ip_fw *chain)
{
char *comma;
u_long adrt;
struct hostent *he;
struct protoent *pe;
int i, mb;
+ int nsp = IP_FW_GETNSRCP(chain);
+ int ndp = IP_FW_GETNDSTP(chain);
if (do_resolv)
setservent(1/*stayopen*/);
@@ -138,17 +199,28 @@ show_ipfw(chain)
case IP_FW_F_ACCEPT:
printf("allow");
break;
- case IP_FW_F_DIVERT:
- printf("divert %u", chain->fw_divert_port);
+ case IP_FW_F_DENY:
+ printf("deny");
break;
case IP_FW_F_COUNT:
printf("count");
break;
- case IP_FW_F_DENY:
- if (chain->fw_flg & IP_FW_F_ICMPRPL)
- printf("reject");
- else
- printf("deny");
+ 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_REJECT:
+ if (chain->fw_reject_code == IP_FW_REJECT_RST)
+ printf("reset");
+ else {
+ printf("unreach ");
+ print_reject_code(chain->fw_reject_code);
+ }
break;
default:
errx(1, "impossible");
@@ -161,7 +233,7 @@ show_ipfw(chain)
if (pe)
printf(" %s", pe->p_name);
else
- printf("%u", chain->fw_prot);
+ printf(" %u", chain->fw_prot);
printf(" from %s", chain->fw_flg & IP_FW_F_INVSRC ? "not " : "");
@@ -192,9 +264,9 @@ show_ipfw(chain)
printf(inet_ntoa(chain->fw_src));
}
- if (chain->fw_prot != IPPROTO_IP) {
+ if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) {
comma = " ";
- for (i=0;i<chain->fw_nsp; i++ ) {
+ for (i = 0; i < nsp; i++) {
print_port(chain->fw_prot, chain->fw_pts[i], comma);
if (i==0 && (chain->fw_flg & IP_FW_F_SRNG))
comma = "-";
@@ -232,35 +304,36 @@ show_ipfw(chain)
printf(inet_ntoa(chain->fw_dst));
}
- comma = " ";
- for (i=0;i<chain->fw_ndp;i++) {
- print_port(chain->fw_prot, chain->fw_pts[chain->fw_nsp+i],
- comma);
- if (i==0 && (chain->fw_flg & IP_FW_F_DRNG))
- comma = "-";
- else
- comma = ",";
- }
+ 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_pts[nsp+i], comma);
+ if (i==0 && (chain->fw_flg & IP_FW_F_DRNG))
+ comma = "-";
+ else
+ comma = ",";
+ }
+ }
- if ((chain->fw_flg & IP_FW_F_IN) && (chain->fw_flg & IP_FW_F_OUT))
- ;
- else if (chain->fw_flg & IP_FW_F_IN)
+ /* Direction */
+ if ((chain->fw_flg & IP_FW_F_IN) && !(chain->fw_flg & IP_FW_F_OUT))
printf(" in");
- else if (chain->fw_flg & IP_FW_F_OUT)
+ if (!(chain->fw_flg & IP_FW_F_IN) && (chain->fw_flg & IP_FW_F_OUT))
printf(" out");
- if (chain->fw_flg&IP_FW_F_IFNAME && chain->fw_via_name[0]) {
- char ifnb[FW_IFNLEN+1];
- printf(" via ");
- strncpy(ifnb,chain->fw_via_name,FW_IFNLEN);
- ifnb[FW_IFNLEN]='\0';
- if (chain->fw_flg & IP_FW_F_IFUWILD)
- printf("%s*",ifnb);
- else
- printf("%s%d",ifnb,chain->fw_via_unit);
- } else if (chain->fw_via_ip.s_addr) {
- printf(" via ");
- printf(inet_ntoa(chain->fw_via_ip));
+ /* Handle hack for "via" backwards compatibility */
+ if ((chain->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
+ print_iface("via",
+ &chain->fw_in_if, chain->fw_flg & IP_FW_F_IIFNAME);
+ } 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);
}
if (chain->fw_flg & IP_FW_F_FRAG)
@@ -342,44 +415,50 @@ list(ac, av)
show_ipfw(r);
}
-void
-show_usage(str)
- char *str;
+static void
+show_usage(const char *fmt, ...)
{
- if (str)
- fprintf(stderr,"%s: ERROR - %s\n",progname,str);
+ if (fmt) {
+ char buf[100];
+ va_list args;
+
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ warnx("error: %s", buf);
+ } else
+ warnx("error");
fprintf(stderr,
"Usage:\n"
-"\t%s [options]\n"
-"\t\tflush\n"
-"\t\tadd [number] rule\n"
-"\t\tdelete number\n"
-"\t\tlist [number]\n"
-"\t\tshow [number]\n"
-"\t\tzero [number]\n"
-"\trule:\taction proto src dst extras...\n"
-"\t\taction: {allow|deny|reject|count|divert port} [log]\n"
-"\t\tproto: {ip|tcp|udp|icmp|<number>}}\n"
-"\t\tsrc: from {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
-"\t\tdst: to {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
-"\textras:\n"
-"\t\tfragment\n"
-"\t\t{in|out|inout}\n"
-"\t\tvia {ifname|ip}\n"
-"\t\t{established|setup}\n"
-"\t\ttcpflags [!]{syn|fin|rst|ack|psh|urg},...\n"
-"\t\tipoptions [!]{ssrr|lsrr|rr|ts},...\n"
-"\t\ticmptypes {type},...\n"
-"\t\tproto {ipproto},...\n"
-, progname
-);
-
-
- fprintf(stderr,"See man %s(8) for proper usage.\n",progname);
- exit (1);
+" %s [options]\n"
+" flush\n"
+" add [number] rule\n"
+" delete number ...\n"
+" list [number]\n"
+" show [number]\n"
+" zero [number ...]\n"
+" rule: 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} [log]\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"
+" extras:\n"
+" fragment\n"
+" in\n"
+" out\n"
+" {xmit|recv|via} {iface|ip|any}\n"
+" {established|setup}\n"
+" tcpflags [!]{syn|fin|rst|ack|psh|urg},...\n"
+" ipoptions [!]{ssrr|lsrr|rr|ts},...\n"
+" icmptypes {type[,type]}...\n",
+__progname);
+
+ errx(1, "see man %s(8) for proper usage.", __progname);
}
-int
+static int
lookup_host (host, ipaddr)
char *host;
struct in_addr *ipaddr;
@@ -415,22 +494,25 @@ fill_ip(ipno, mask, acp, avp)
*p++ = '\0';
}
- if (lookup_host(*av,ipno) != 0)
- show_usage("ip number\n");
+ if (lookup_host(*av, ipno) != 0)
+ show_usage("hostname ``%s'' unknown", *av);
switch (md) {
case ':':
if (!inet_aton(p,mask))
- show_usage("ip number\n");
+ show_usage("bad netmask ``%s''", p);
break;
case '/':
if (atoi(p) == 0) {
mask->s_addr = 0;
+ } else if (atoi(p) > 32) {
+ show_usage("bad width ``%s''", p);
} else {
- mask->s_addr = htonl(0xffffffff << (32 - atoi(p)));
+ mask->s_addr =
+ htonl(~0 << (32 - atoi(p)));
}
break;
default:
- mask->s_addr = htonl(0xffffffff);
+ mask->s_addr = htonl(~0);
break;
}
ipno->s_addr &= mask->s_addr;
@@ -441,7 +523,27 @@ fill_ip(ipno, mask, acp, avp)
*avp = av;
}
-void
+static void
+fill_reject_code(u_short *codep, char *str)
+{
+ struct icmpcode *ic;
+ u_long val;
+ char *s;
+
+ 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;
+ }
+ show_usage("unknown ICMP unreachable code ``%s''", str);
+}
+
+static void
add_port(cnt, ptr, off, port)
u_short *cnt, *ptr, off, port;
{
@@ -520,15 +622,13 @@ fill_tcpflag(set, reset, vp)
break;
}
if (i == sizeof(flags) / sizeof(flags[0]))
- show_usage("invalid tcp flag\n");
+ show_usage("invalid tcp flag ``%s''", p);
p = q;
}
}
-void
-fill_ipopt(set, reset, vp)
- u_char *set, *reset;
- char **vp;
+static void
+fill_ipopt(u_char *set, u_char *reset, char **vp)
{
char *p = *vp,*q;
u_char *d;
@@ -593,18 +693,16 @@ delete(ac,av)
av++; ac--;
/* Rule number */
- if (ac && isdigit(**av)) {
+ while (ac && isdigit(**av)) {
rule.fw_number = atoi(*av); av++; ac--;
+ i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule);
+ if (i)
+ warn("setsockopt(%s)", "IP_FW_DEL");
}
-
- i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule);
- if (i)
- err(1,"setsockopt(IP_FW_DEL)");
}
-int
-verify_interface(rule)
- struct ip_fw *rule;
+static void
+verify_interface(union ip_fw_if *ifu)
{
struct ifreq ifr;
@@ -613,16 +711,42 @@ verify_interface(rule)
* If a wildcard was specified, check for unit 0.
*/
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
- rule->fw_via_name,
- rule->fw_flg & IP_FW_F_IFUWILD ? 0 : rule->fw_via_unit);
+ ifu->fu_via_if.name,
+ ifu->fu_via_if.unit == -1 ? 0 : ifu->fu_via_if.unit);
if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
- return(-1); /* interface isn't recognized by the kernel */
+ warnx("warning: interface ``%s'' does not exist", ifr.ifr_name);
+}
- return(0); /* interface exists */
+static void
+fill_iface(char *which, union ip_fw_if *ifu, int *byname, int ac, char *arg)
+{
+ if (!ac)
+ show_usage("missing argument for ``%s''", which);
+
+ /* 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;
+ strncpy(ifu->fu_via_if.name, arg, sizeof(ifu->fu_via_if.name));
+ 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)) {
+ show_usage("bad ip address ``%s''", arg);
+ } else
+ *byname = 0;
}
-void
+static void
add(ac,av)
int ac;
char **av;
@@ -631,6 +755,7 @@ add(ac,av)
int i;
u_char proto;
struct protoent *pe;
+ int saw_xmrc = 0, saw_via = 0;
memset(&rule, 0, sizeof rule);
@@ -642,26 +767,48 @@ add(ac,av)
}
/* Action */
- if (ac && (!strncmp(*av,"accept",strlen(*av))
+ 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)))) {
+ || !strncmp(*av,"permit",strlen(*av))) {
rule.fw_flg |= IP_FW_F_ACCEPT; av++; ac--;
- } else if (ac && !strncmp(*av,"count",strlen(*av))) {
+ } else if (!strncmp(*av,"count",strlen(*av))) {
rule.fw_flg |= IP_FW_F_COUNT; av++; ac--;
- } else if (ac && !strncmp(*av,"divert",strlen(*av))) {
+ } else if (!strncmp(*av,"divert",strlen(*av))) {
rule.fw_flg |= IP_FW_F_DIVERT; av++; ac--;
if (!ac)
show_usage("missing divert port");
rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
if (rule.fw_divert_port == 0)
show_usage("illegal divert port");
- } else if (ac && (!strncmp(*av,"deny",strlen(*av)))) {
+ } else if (!strncmp(*av,"tee",strlen(*av))) {
+ rule.fw_flg |= IP_FW_F_TEE; av++; ac--;
+ if (!ac)
+ show_usage("missing divert port");
+ rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--;
+ if (rule.fw_divert_port == 0)
+ show_usage("illegal divert port");
+ } 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)))) {
rule.fw_flg |= IP_FW_F_DENY; av++; ac--;
- } else if (ac && !strncmp(*av,"reject",strlen(*av))) {
- rule.fw_flg |= IP_FW_F_DENY|IP_FW_F_ICMPRPL; av++; ac--;
+ } 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))) {
+ 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))) {
+ rule.fw_flg |= IP_FW_F_REJECT; av++; ac--;
+ fill_reject_code(&rule.fw_reject_code, *av); av++; ac--;
} else {
- show_usage("missing/unrecognized action\n");
+ show_usage("invalid action ``%s''", *av);
}
/* [log] */
@@ -670,103 +817,142 @@ add(ac,av)
}
/* protocol */
- if (ac) {
- if ((proto = atoi(*av)) > 0) {
- rule.fw_prot = proto; av++; ac--;
- } 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--;
- } else {
- show_usage("invalid protocol\n");
- }
- } else
- show_usage("missing protocol\n");
+ 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))) {
+ rule.fw_prot = IPPROTO_IP; av++; ac--;
+ } else if ((pe = getprotobyname(*av)) != NULL) {
+ rule.fw_prot = pe->p_proto; av++; ac--;
+ } else {
+ show_usage("invalid protocol ``%s''", *av);
+ }
+
+ 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)
+ show_usage("``reset'' is only valid for tcp packets");
/* from */
if (ac && !strncmp(*av,"from",strlen(*av))) { av++; ac--; }
- else show_usage("missing ``from''\n");
+ else
+ show_usage("missing ``from''");
if (ac && !strncmp(*av,"not",strlen(*av))) {
rule.fw_flg |= IP_FW_F_INVSRC;
av++; ac--;
}
- if (!ac) show_usage("Missing arguments\n");
+ if (!ac)
+ show_usage("missing arguments");
fill_ip(&rule.fw_src, &rule.fw_smsk, &ac, &av);
if (ac && isdigit(**av)) {
- if (fill_port(&rule.fw_nsp, &rule.fw_pts, 0, *av, 0))
+ u_short nports = 0;
+
+ if (fill_port(&nports, rule.fw_pts, 0, *av))
rule.fw_flg |= IP_FW_F_SRNG;
+ IP_FW_SETNSRCP(&rule, nports);
av++; ac--;
}
/* to */
if (ac && !strncmp(*av,"to",strlen(*av))) { av++; ac--; }
- else show_usage("missing ``to''\n");
+ else
+ show_usage("missing ``to''");
if (ac && !strncmp(*av,"not",strlen(*av))) {
rule.fw_flg |= IP_FW_F_INVDST;
av++; ac--;
}
- if (!ac) show_usage("Missing arguments\n");
+ if (!ac)
+ show_usage("missing arguments");
fill_ip(&rule.fw_dst, &rule.fw_dmsk, &ac, &av);
if (ac && isdigit(**av)) {
- if (fill_port(&rule.fw_ndp, &rule.fw_pts, rule.fw_nsp, *av, 0))
+ u_short nports = 0;
+
+ if (fill_port(&nports,
+ rule.fw_pts, IP_FW_GETNSRCP(&rule), *av))
rule.fw_flg |= IP_FW_F_DRNG;
+ IP_FW_SETNDSTP(&rule, nports);
av++; ac--;
}
- if ((rule.fw_prot != IPPROTO_TCP) &&
- (rule.fw_prot != IPPROTO_UDP) &&
- (rule.fw_nsp || rule.fw_ndp)) {
- show_usage("only TCP and UDP protocols are valid with port specifications");
+ if ((rule.fw_prot != IPPROTO_TCP) && (rule.fw_prot != IPPROTO_UDP)
+ && (IP_FW_GETNSRCP(&rule) || IP_FW_GETNDSTP(&rule))) {
+ show_usage("only TCP and UDP protocols are valid"
+ " with port specifications");
}
while (ac) {
- if (ac && !strncmp(*av,"via",strlen(*av))) {
- if (rule.fw_via_ip.s_addr || (rule.fw_flg & IP_FW_F_IFNAME)) {
- show_usage("multiple 'via' options specified");
- }
-
- av++; ac--;
- if (!ac) {
- show_usage("'via' option specified with no interface.");
- }
- if (!isdigit(**av)) {
- char *q;
-
- strncpy(rule.fw_via_name, *av, sizeof(rule.fw_via_name));
- rule.fw_via_name[sizeof(rule.fw_via_name) - 1] = '\0';
- for (q = rule.fw_via_name; *q && !isdigit(*q) && *q != '*'; q++)
- continue;
- if (*q == '*')
- rule.fw_flg |= IP_FW_F_IFUWILD;
- else
- rule.fw_via_unit = atoi(q);
- *q = '\0';
- rule.fw_flg |= IP_FW_F_IFNAME;
- if (verify_interface(&rule) != 0)
- fprintf(stderr, "Warning: interface does not exist\n");
- } else if (inet_aton(*av,&rule.fw_via_ip) == INADDR_NONE) {
- show_usage("bad IP# after via\n");
+ if (!strncmp(*av,"in",strlen(*av))) {
+ rule.fw_flg |= IP_FW_F_IN;
+ 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))) {
+ union ip_fw_if ifu;
+ int byname;
+
+ if (saw_via) {
+badviacombo:
+ show_usage("``via'' is incompatible"
+ " with ``xmit'' and ``recv''");
}
+ saw_xmrc = 1;
av++; ac--;
- continue;
+ 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;
+ av++; ac--; continue;
}
- if (!strncmp(*av,"fragment",strlen(*av))) {
- rule.fw_flg |= IP_FW_F_FRAG; av++; ac--; continue;
+ if (ac && !strncmp(*av,"recv",strlen(*av))) {
+ union ip_fw_if ifu;
+ int byname;
+
+ if (saw_via)
+ goto badviacombo;
+ saw_xmrc = 1;
+ av++; ac--;
+ 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;
+ av++; ac--; continue;
}
- if (!strncmp(*av,"in",strlen(*av))) {
- rule.fw_flg |= IP_FW_F_IN; av++; ac--; continue;
+ 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--;
+ 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);
+ av++; ac--; continue;
}
- if (!strncmp(*av,"out",strlen(*av))) {
- rule.fw_flg |= IP_FW_F_OUT; av++; ac--; continue;
+ if (!strncmp(*av,"fragment",strlen(*av))) {
+ rule.fw_flg |= IP_FW_F_FRAG;
+ av++; ac--; continue;
}
- if (ac > 1 && !strncmp(*av,"ipoptions",strlen(*av))) {
+ if (!strncmp(*av,"ipoptions",strlen(*av))) {
av++; ac--;
+ if (!ac)
+ show_usage("missing argument"
+ " for ``ipoptions''");
fill_ipopt(&rule.fw_ipopt, &rule.fw_ipnopt, av);
av++; ac--; continue;
}
@@ -780,31 +966,50 @@ add(ac,av)
rule.fw_tcpnf |= IP_FW_TCPF_ACK;
av++; ac--; continue;
}
- if (ac > 1 && !strncmp(*av,"tcpflags",strlen(*av))) {
+ if (!strncmp(*av,"tcpflags",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 (rule.fw_prot == IPPROTO_ICMP) {
- if (ac > 1 && !strncmp(*av,"icmptypes",strlen(*av))) {
+ if (!strncmp(*av,"icmptypes",strlen(*av))) {
av++; ac--;
- fill_icmptypes(rule.fw_icmptypes, av, &rule.fw_flg);
+ if (!ac)
+ show_usage("missing argument"
+ " for ``icmptypes''");
+ fill_icmptypes(rule.fw_icmptypes,
+ av, &rule.fw_flg);
av++; ac--; continue;
}
}
- printf("%d %s\n",ac,*av);
- show_usage("Unknown argument\n");
+ show_usage("unknown argument ``%s''", *av);
}
+ /* 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;
+ } else if ((rule.fw_flg & IP_FW_F_OIFACE) && (rule.fw_flg & IP_FW_F_IN))
+ show_usage("can't check xmit interface of incoming packets");
+
if (!do_quiet)
show_ipfw(&rule);
i = setsockopt(s, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
if (i)
- err(1,"setsockopt(IP_FW_ADD)");
+ err(1, "setsockopt(%s)", "IP_FW_ADD");
}
-void
+static void
zero (ac, av)
int ac;
char **av;
@@ -813,28 +1018,26 @@ zero (ac, av)
if (!ac) {
/* clear all entries */
- if (setsockopt(s,IPPROTO_IP,IP_FW_ZERO,NULL,0)<0) {
- fprintf(stderr,"%s: setsockopt failed.\n",progname);
- exit(1);
- }
+ if (setsockopt(s,IPPROTO_IP,IP_FW_ZERO,NULL,0)<0)
+ err(1, "setsockopt(%s)", "IP_FW_ZERO");
if (!do_quiet)
printf("Accounting cleared.\n");
} else {
- /* clear a specific entry */
struct ip_fw rule;
memset(&rule, 0, sizeof rule);
-
- /* Rule number */
- if (isdigit(**av)) {
- rule.fw_number = atoi(*av); av++; ac--;
-
- if (setsockopt(s, IPPROTO_IP, IP_FW_ZERO, &rule, sizeof rule))
- err(1, "setsockopt(Zero)");
- printf("Entry %d cleared\n", rule.fw_number);
- }
- else {
- show_usage("expected number");
+ 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("setsockopt(%s)", "IP_FW_ZERO");
+ else
+ printf("Entry %d cleared\n",
+ rule.fw_number);
+ } else
+ show_usage("invalid rule number ``%s''", *av);
}
}
}
@@ -874,7 +1077,7 @@ ipfw_main(ac,av)
do_resolv=1;
break;
default:
- show_usage("Unrecognised switch");
+ show_usage("invalid flag ``-%c''", ch);
}
ac -= optind;
@@ -908,10 +1111,8 @@ ipfw_main(ac,av)
do_flush = 1;
}
if ( do_flush ) {
- if (setsockopt(s,IPPROTO_IP,IP_FW_FLUSH,NULL,0)<0) {
- fprintf(stderr,"%s: setsockopt failed.\n",progname);
- exit(1);
- }
+ if (setsockopt(s,IPPROTO_IP,IP_FW_FLUSH,NULL,0) < 0)
+ err(1, "setsockopt(%s)", "IP_FW_FLUSH");
if (!do_quiet)
printf("Flushed all rules.\n");
}
@@ -936,47 +1137,34 @@ main(ac, av)
char **av;
{
#define MAX_ARGS 32
+#define WHITESP " \t\f\v\n\r"
char buf[BUFSIZ];
- char *args[MAX_ARGS];
+ char *a, *args[MAX_ARGS];
char linename[10];
int i;
FILE *f;
- strncpy(progname,*av, sizeof(progname));
- progname[sizeof(progname) - 1] = '\0';
-
s = socket( AF_INET, SOCK_RAW, IPPROTO_RAW );
- if ( s < 0 ) {
- fprintf(stderr,"%s: Can't open raw socket.\n"
- "Must be root to use this program.\n",progname);
- exit(1);
- }
+ if ( s < 0 )
+ err(1, "socket");
setbuf(stdout,0);
if (av[1] && !access(av[1], R_OK)) {
lineno = 0;
- f = fopen(av[1], "r");
+ if ((f = fopen(av[1], "r")) == NULL)
+ err(1, "fopen: %s", av[1]);
while (fgets(buf, BUFSIZ, f)) {
- if (buf[strlen(buf)-1]=='\n')
- buf[strlen(buf)-1] = 0;
lineno++;
sprintf(linename, "Line %d", lineno);
args[0] = linename;
- args[1] = buf;
- while(*args[1] == ' ')
- args[1]++;
- i = 2;
- while((args[i] = strchr(args[i-1],' '))) {
- *(args[i]++) = 0;
- while(*args[i] == ' ')
- args[i]++;
- i++;
- }
- if (*args[i-1] == 0)
- i--;
+ for (i = 1, a = strtok(buf, WHITESP);
+ a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++)
+ args[i] = a;
+ if (i == MAX_ARGS)
+ errx(1, "%s: too many arguments", linename);
args[i] = NULL;
ipfw_main(i, args);
OpenPOWER on IntegriCloud