aboutsummaryrefslogtreecommitdiff
path: root/contrib/ipfilter/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ipfilter/parse.c')
-rw-r--r--contrib/ipfilter/parse.c270
1 files changed, 222 insertions, 48 deletions
diff --git a/contrib/ipfilter/parse.c b/contrib/ipfilter/parse.c
index 56bc3fcb5f2b..6a2a04ed5327 100644
--- a/contrib/ipfilter/parse.c
+++ b/contrib/ipfilter/parse.c
@@ -3,6 +3,9 @@
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
+#ifdef __sgi
+# include <sys/ptimers.h>
+#endif
#include <sys/types.h>
#if !defined(__SVR4) && !defined(__svr4__)
#include <strings.h>
@@ -44,9 +47,7 @@ static const char rcsid[] = "@(#)$IPFilter: parse.c,v 2.8 1999/12/28 10:49:46 da
extern struct ipopt_names ionames[], secclass[];
extern int opts;
-#ifdef USE_INET6
extern int use_inet6;
-#endif
int addicmp __P((char ***, struct frentry *, int));
int extras __P((char ***, struct frentry *, int));
@@ -57,6 +58,7 @@ void print_toif __P((char *, frdest_t *));
void optprint __P((u_short *, u_long, u_long));
int loglevel __P((char **, u_int *, int));
void printlog __P((frentry_t *));
+void printifname __P((char *, char *, void *));
extern char *proto;
extern char flagset[];
@@ -72,8 +74,8 @@ char *line;
int linenum;
{
static struct frentry fil;
+ char *cps[31], **cpp, *endptr, *s;
struct protoent *p = NULL;
- char *cps[31], **cpp, *endptr;
int i, cnt = 1, j, ch;
u_int k;
@@ -84,11 +86,7 @@ int linenum;
bzero((char *)&fil, sizeof(fil));
fil.fr_mip.fi_v = 0xf;
-#ifdef USE_INET6
fil.fr_ip.fi_v = use_inet6 ? 6 : 4;
-#else
- fil.fr_ip.fi_v = 4;
-#endif
fil.fr_loglevel = 0xffff;
/*
@@ -106,10 +104,18 @@ int linenum;
}
cpp = cps;
+ /*
+ * The presence of an '@' followed by a number gives the position in
+ * the current rule list to insert this one.
+ */
if (**cpp == '@')
fil.fr_hits = (U_QUAD_T)atoi(*cpp++ + 1) + 1;
+ /*
+ * Check the first keyword in the rule and any options that are
+ * expected to follow it.
+ */
if (!strcasecmp("block", *cpp)) {
fil.fr_flags |= FR_BLOCK;
if (!strncasecmp(*(cpp+1), "return-icmp-as-dest", 19) &&
@@ -149,6 +155,8 @@ int linenum;
fil.fr_flags |= FR_ACCOUNT;
} else if (!strcasecmp("pass", *cpp)) {
fil.fr_flags |= FR_PASS;
+ } else if (!strcasecmp("nomatch", *cpp)) {
+ fil.fr_flags |= FR_NOMATCH;
} else if (!strcasecmp("auth", *cpp)) {
fil.fr_flags |= FR_AUTH;
} else if (!strcasecmp("preauth", *cpp)) {
@@ -194,6 +202,10 @@ int linenum;
return NULL;
}
+ /*
+ * Get the direction for filtering. Impose restrictions on direction
+ * if blocking with returning ICMP or an RST has been requested.
+ */
if (!strcasecmp("in", *cpp))
fil.fr_flags |= FR_INQUE;
else if (!strcasecmp("out", *cpp)) {
@@ -252,19 +264,39 @@ int linenum;
}
if (*cpp && !strcasecmp("quick", *cpp)) {
+ if (fil.fr_skip != 0) {
+ fprintf(stderr, "%d: cannot use skip with quick\n",
+ linenum);
+ return NULL;
+ }
cpp++;
fil.fr_flags |= FR_QUICK;
}
+ /*
+ * Parse rule options that are available if a rule is tied to an
+ * interface.
+ */
*fil.fr_ifname = '\0';
+ *fil.fr_oifname = '\0';
if (*cpp && !strcasecmp(*cpp, "on")) {
if (!*++cpp) {
fprintf(stderr, "%d: interface name missing\n",
linenum);
return NULL;
}
- (void)strncpy(fil.fr_ifname, *cpp, IFNAMSIZ-1);
- fil.fr_ifname[IFNAMSIZ-1] = '\0';
+
+ s = index(*cpp, ',');
+ if (s != NULL) {
+ *s++ = '\0';
+ (void)strncpy(fil.fr_ifnames[1], s, IFNAMSIZ - 1);
+ fil.fr_ifnames[1][IFNAMSIZ - 1] = '\0';
+ } else
+ strcpy(fil.fr_ifnames[1], "*");
+
+ (void)strncpy(fil.fr_ifnames[0], *cpp, IFNAMSIZ - 1);
+ fil.fr_ifnames[0][IFNAMSIZ - 1] = '\0';
+
cpp++;
if (!*cpp) {
if ((fil.fr_flags & FR_RETMASK) == FR_RETRST) {
@@ -299,6 +331,33 @@ int linenum;
cpp++;
}
}
+
+ /*
+ * Set the "other" interface name. Lets you specify both
+ * inbound and outbound interfaces for state rules. Do not
+ * prevent both interfaces from being the same.
+ */
+ strcpy(fil.fr_ifnames[3], "*");
+ if ((*cpp != NULL) && (*(cpp + 1) != NULL) &&
+ ((((fil.fr_flags & FR_INQUE) != 0) &&
+ (strcasecmp(*cpp, "out-via") == 0)) ||
+ (((fil.fr_flags & FR_OUTQUE) != 0) &&
+ (strcasecmp(*cpp, "in-via") == 0)))) {
+ cpp++;
+
+ s = index(*cpp, ',');
+ if (s != NULL) {
+ *s++ = '\0';
+ (void)strncpy(fil.fr_ifnames[3], s,
+ IFNAMSIZ - 1);
+ fil.fr_ifnames[3][IFNAMSIZ - 1] = '\0';
+ }
+
+ (void)strncpy(fil.fr_ifnames[2], *cpp, IFNAMSIZ - 1);
+ fil.fr_ifnames[2][IFNAMSIZ - 1] = '\0';
+ cpp++;
+ } else
+ strcpy(fil.fr_ifnames[2], "*");
}
if (*cpp && !strcasecmp(*cpp, "tos")) {
if (!*++cpp) {
@@ -340,6 +399,10 @@ int linenum;
if (!strcasecmp(proto, "tcp/udp")) {
fil.fr_ip.fi_fl |= FI_TCPUDP;
fil.fr_mip.fi_fl |= FI_TCPUDP;
+ } else if (use_inet6 && !strcasecmp(proto, "icmp")) {
+ fprintf(stderr,
+"%d: use proto ipv6-icmp with IPv6 (or use proto 1 if you really mean icmp)\n",
+ linenum);
} else {
if (!(p = getprotobyname(proto)) && !isdigit(*proto)) {
fprintf(stderr,
@@ -411,6 +474,15 @@ int linenum;
return NULL;
}
+ if ((ch != 0) && (fil.fr_proto != IPPROTO_TCP) &&
+ (fil.fr_proto != IPPROTO_UDP) &&
+ !(fil.fr_ip.fi_fl & FI_TCPUDP)) {
+ fprintf(stderr,
+ "%d: cannot use port and neither tcp or udp\n",
+ linenum);
+ return NULL;
+ }
+
fil.fr_scmp = ch;
if (!*cpp) {
fprintf(stderr, "%d: missing to fields\n", linenum);
@@ -447,6 +519,15 @@ int linenum;
&fil.fr_dtop, linenum)) {
return NULL;
}
+ if ((ch != 0) && (fil.fr_proto != IPPROTO_TCP) &&
+ (fil.fr_proto != IPPROTO_UDP) &&
+ !(fil.fr_ip.fi_fl & FI_TCPUDP)) {
+ fprintf(stderr,
+ "%d: cannot use port and neither tcp or udp\n",
+ linenum);
+ return NULL;
+ }
+
fil.fr_dcmp = ch;
}
@@ -489,7 +570,8 @@ int linenum;
* icmp types for use with the icmp protocol
*/
if (*cpp && !strcasecmp(*cpp, "icmp-type")) {
- if (fil.fr_proto != IPPROTO_ICMP) {
+ if (fil.fr_proto != IPPROTO_ICMP &&
+ fil.fr_proto != IPPROTO_ICMPV6) {
fprintf(stderr,
"%d: icmp with wrong protocol (%d)\n",
linenum, fil.fr_proto);
@@ -509,9 +591,27 @@ int linenum;
return NULL;
/*
+ * This is here to enforce the old interface binding behaviour.
+ * That is, "on X" is equivalent to "<dir> on X <!dir>-via -,X"
+ */
+ if (fil.fr_flags & FR_KEEPSTATE) {
+ if (*fil.fr_ifnames[0] && !*fil.fr_ifnames[3]) {
+ bcopy(fil.fr_ifnames[0], fil.fr_ifnames[3],
+ sizeof(fil.fr_ifnames[3]));
+ strncpy(fil.fr_ifnames[2], "*",
+ sizeof(fil.fr_ifnames[3]));
+ }
+ }
+
+ /*
* head of a new group ?
*/
if (*cpp && !strcasecmp(*cpp, "head")) {
+ if (fil.fr_skip != 0) {
+ fprintf(stderr, "%d: cannot use skip with head\n",
+ linenum);
+ return NULL;
+ }
if (!*++cpp) {
fprintf(stderr, "%d: head without group #\n", linenum);
return NULL;
@@ -658,6 +758,15 @@ frdest_t *fdp;
{
printf("%s %s%s", tag, fdp->fd_ifname,
(fdp->fd_ifp || (long)fdp->fd_ifp == -1) ? "" : "(!)");
+#ifdef USE_INET6
+ if (use_inet6 && IP6_NOTZERO(&fdp->fd_ip6.in6)) {
+ char ipv6addr[80];
+
+ inet_ntop(AF_INET6, &fdp->fd_ip6, ipv6addr,
+ sizeof(fdp->fd_ip6));
+ printf(":%s", ipv6addr);
+ } else
+#endif
if (fdp->fd_ip.s_addr)
printf(":%s", inet_ntoa(fdp->fd_ip));
putchar(' ');
@@ -685,9 +794,9 @@ int linenum;
return -1;
while (**cp && (!strncasecmp(**cp, "ipopt", 5) ||
- !strncasecmp(**cp, "not", 3) || !strncasecmp(**cp, "opt", 3) ||
- !strncasecmp(**cp, "frag", 4) || !strncasecmp(**cp, "no", 2) ||
- !strncasecmp(**cp, "short", 5))) {
+ !strcasecmp(**cp, "not") || !strncasecmp(**cp, "opt", 3) ||
+ !strncasecmp(**cp, "frag", 4) || !strcasecmp(**cp, "no") ||
+ !strcasecmp(**cp, "short"))) {
if (***cp == 'n' || ***cp == 'N') {
notopt = 1;
(*cp)++;
@@ -899,10 +1008,10 @@ char *icmptypes[] = {
/*
* set the icmp field to the correct type if "icmp" word is found
*/
-int addicmp(cp, fp, linenum)
-char ***cp;
-struct frentry *fp;
-int linenum;
+int addicmp(cp, fp, linenum)
+char ***cp;
+struct frentry *fp;
+int linenum;
{
char **t;
int i;
@@ -910,8 +1019,7 @@ int linenum;
(*cp)++;
if (!**cp)
return -1;
- if (!fp->fr_proto) /* to catch lusers */
- fp->fr_proto = IPPROTO_ICMP;
+
if (isdigit(***cp)) {
if (!ratoi(**cp, &i, 0, 255)) {
fprintf(stderr,
@@ -919,6 +1027,10 @@ int linenum;
linenum, **cp);
return -1;
}
+ } else if (fp->fr_proto == IPPROTO_ICMPV6) {
+ fprintf(stderr, "%d: Unknown ICMPv6 type (%s) specified, %s",
+ linenum, **cp, "(use numeric value instead\n");
+ return -1;
} else {
for (t = icmptypes, i = 0; ; t++, i++) {
if (!*t)
@@ -973,10 +1085,10 @@ int linenum;
#define MAX_ICMPCODE 15
char *icmpcodes[] = {
- "net-unr", "host-unr", "proto-unr", "port-unr", "needfrag", "srcfail",
- "net-unk", "host-unk", "isolate", "net-prohib", "host-prohib",
- "net-tos", "host-tos", "filter-prohib", "host-preced", "preced-cutoff",
- NULL };
+ "net-unr", "host-unr", "proto-unr", "port-unr", "needfrag",
+ "srcfail", "net-unk", "host-unk", "isolate", "net-prohib",
+ "host-prohib", "net-tos", "host-tos", "filter-prohib", "host-preced",
+ "preced-cutoff", NULL };
/*
* Return the number for the associated ICMP unreachable code.
*/
@@ -1006,47 +1118,73 @@ char *str;
/*
* set the icmp field to the correct type if "icmp" word is found
*/
-int addkeep(cp, fp, linenum)
-char ***cp;
-struct frentry *fp;
-int linenum;
+int addkeep(cp, fp, linenum)
+char ***cp;
+struct frentry *fp;
+int linenum;
{
- if (fp->fr_proto != IPPROTO_TCP && fp->fr_proto != IPPROTO_UDP &&
-#ifdef USE_INET6
- fp->fr_proto != IPPROTO_ICMPV6 &&
-#endif
- fp->fr_proto != IPPROTO_ICMP && !(fp->fr_ip.fi_fl & FI_TCPUDP)) {
- fprintf(stderr, "%d: Can only use keep with UDP/ICMP/TCP\n",
- linenum);
- return -1;
- }
+ char *s;
(*cp)++;
if (!**cp) {
- fprintf(stderr, "%d: Missing state/frag after keep\n",
+ fprintf(stderr, "%d: Missing keyword after keep\n",
linenum);
return -1;
}
- if (strcasecmp(**cp, "state") && strcasecmp(**cp, "frags")) {
+
+ if (strcasecmp(**cp, "state") == 0)
+ fp->fr_flags |= FR_KEEPSTATE;
+ else if (strncasecmp(**cp, "frag", 4) == 0)
+ fp->fr_flags |= FR_KEEPFRAG;
+ else if (strcasecmp(**cp, "state-age") == 0) {
+ if (fp->fr_ip.fi_p == IPPROTO_TCP) {
+ fprintf(stderr, "%d: cannot use state-age with tcp\n",
+ linenum);
+ return -1;
+ }
+ if ((fp->fr_flags & FR_KEEPSTATE) == 0) {
+ fprintf(stderr, "%d: state-age with no 'keep state'\n",
+ linenum);
+ return -1;
+ }
+ (*cp)++;
+ if (!**cp) {
+ fprintf(stderr, "%d: state-age with no arg\n",
+ linenum);
+ return -1;
+ }
+ fp->fr_age[0] = atoi(**cp);
+ s = index(**cp, '/');
+ if (s != NULL) {
+ s++;
+ fp->fr_age[1] = atoi(s);
+ } else
+ fp->fr_age[1] = fp->fr_age[0];
+ } else {
fprintf(stderr, "%d: Unrecognised state keyword \"%s\"\n",
linenum, **cp);
return -1;
}
-
- if (***cp == 's' || ***cp == 'S')
- fp->fr_flags |= FR_KEEPSTATE;
- else if (***cp == 'f' || ***cp == 'F')
- fp->fr_flags |= FR_KEEPFRAG;
(*cp)++;
return 0;
}
+void printifname(format, name, ifp)
+char *format, *name;
+void *ifp;
+{
+ printf("%s%s", format, name);
+ if ((ifp == NULL) && strcmp(name, "-") && strcmp(name, "*"))
+ printf("(!)");
+}
+
+
/*
* print the filter structure in a useful way
*/
-void printfr(fp)
-struct frentry *fp;
+void printfr(fp)
+struct frentry *fp;
{
struct protoent *p;
u_short sec[2];
@@ -1056,6 +1194,8 @@ struct frentry *fp;
if (fp->fr_flags & FR_PASS)
printf("pass");
+ if (fp->fr_flags & FR_NOMATCH)
+ printf("nomatch");
else if (fp->fr_flags & FR_BLOCK) {
printf("block");
if (fp->fr_flags & FR_RETICMP) {
@@ -1098,8 +1238,11 @@ struct frentry *fp;
printf("quick ");
if (*fp->fr_ifname) {
- printf("on %s%s ", fp->fr_ifname,
- (fp->fr_ifa || (long)fp->fr_ifa == -1) ? "" : "(!)");
+ printifname("on ", fp->fr_ifname, fp->fr_ifa);
+ if (*fp->fr_ifnames[1] && strcmp(fp->fr_ifnames[1], "*"))
+ printifname(",", fp->fr_ifnames[1], fp->fr_ifas[1]);
+ putchar(' ');
+
if (*fp->fr_dif.fd_ifname)
print_toif("dup-to", &fp->fr_dif);
if (*fp->fr_tif.fd_ifname)
@@ -1107,7 +1250,26 @@ struct frentry *fp;
if (fp->fr_flags & FR_FASTROUTE)
printf("fastroute ");
+ if ((*fp->fr_ifnames[2] && strcmp(fp->fr_ifnames[2], "*")) ||
+ (*fp->fr_ifnames[3] && strcmp(fp->fr_ifnames[3], "*"))) {
+ if (fp->fr_flags & FR_OUTQUE)
+ printf("in-via ");
+ else
+ printf("out-via ");
+
+ if (*fp->fr_ifnames[2]) {
+ printifname("", fp->fr_ifnames[2],
+ fp->fr_ifas[2]);
+ putchar(',');
+ }
+
+ if (*fp->fr_ifnames[3])
+ printifname("", fp->fr_ifnames[3],
+ fp->fr_ifas[3]);
+ putchar(' ');
+ }
}
+
if (fp->fr_mip.fi_tos)
printf("tos %#x ", fp->fr_tos);
if (fp->fr_mip.fi_ttl)
@@ -1161,7 +1323,7 @@ struct frentry *fp;
printf(" frag");
}
}
- if (fp->fr_proto == IPPROTO_ICMP && fp->fr_icmpm) {
+ if (fp->fr_proto == IPPROTO_ICMP && fp->fr_icmpm != 0) {
int type = fp->fr_icmp, code;
type = ntohs(fp->fr_icmp);
@@ -1175,6 +1337,16 @@ struct frentry *fp;
if (ntohs(fp->fr_icmpm) & 0xff)
printf(" code %d", code);
}
+ if (fp->fr_proto == IPPROTO_ICMPV6 && fp->fr_icmpm != 0) {
+ int type = fp->fr_icmp, code;
+
+ type = ntohs(fp->fr_icmp);
+ code = type & 0xff;
+ type /= 256;
+ printf(" icmp-type %d", type);
+ if (ntohs(fp->fr_icmpm) & 0xff)
+ printf(" code %d", code);
+ }
if (fp->fr_proto == IPPROTO_TCP && (fp->fr_tcpf || fp->fr_tcpfm)) {
printf(" flags ");
if (fp->fr_tcpf & ~TCPF_ALL)
@@ -1198,6 +1370,8 @@ struct frentry *fp;
printf(" keep state");
if (fp->fr_flags & FR_KEEPFRAG)
printf(" keep frags");
+ if (fp->fr_age[0] != 0 || fp->fr_age[1]!= 0)
+ printf(" state-age %u/%u", fp->fr_age[0], fp->fr_age[1]);
if (fp->fr_grhead)
printf(" head %d", fp->fr_grhead);
if (fp->fr_group)