Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/usr.sbin/npf/npfctl Full rewrite of npfctl(8) parser and rew...



details:   https://anonhg.NetBSD.org/src/rev/dbabed10ac90
branches:  trunk
changeset: 772568:dbabed10ac90
user:      rmind <rmind%NetBSD.org@localhost>
date:      Sun Jan 08 21:34:21 2012 +0000

description:
Full rewrite of npfctl(8) parser and rework of n-code generation part.
Fixes most of the known bugs and issues with the utility.  Note: rule
procedures are not yet (as we want to make them fully modular).

Huge thanks to Martin Husemann who wrote the parser and Christos Zoulas
who wrote intermediate structures and helped to complete the work.

diffstat:

 usr.sbin/npf/npfctl/Makefile     |   12 +-
 usr.sbin/npf/npfctl/npf_build.c  |  495 ++++++++++++++++++++++
 usr.sbin/npf/npfctl/npf_data.c   |  733 +++++++++++++++-----------------
 usr.sbin/npf/npfctl/npf_ncgen.c  |  384 +++++++++++------
 usr.sbin/npf/npfctl/npf_parse.y  |  713 +++++++++++++++++++++++++++++++
 usr.sbin/npf/npfctl/npf_parser.c |  875 ---------------------------------------
 usr.sbin/npf/npfctl/npf_scan.l   |  155 ++++++
 usr.sbin/npf/npfctl/npf_var.c    |  213 +++++++++
 usr.sbin/npf/npfctl/npf_var.h    |   75 +++
 usr.sbin/npf/npfctl/npfctl.c     |  110 ++--
 usr.sbin/npf/npfctl/npfctl.h     |  148 ++++--
 11 files changed, 2406 insertions(+), 1507 deletions(-)

diffs (truncated from 4324 to 300 lines):

diff -r 0b6eadee9cc5 -r dbabed10ac90 usr.sbin/npf/npfctl/Makefile
--- a/usr.sbin/npf/npfctl/Makefile      Sun Jan 08 21:20:40 2012 +0000
+++ b/usr.sbin/npf/npfctl/Makefile      Sun Jan 08 21:34:21 2012 +0000
@@ -1,14 +1,18 @@
-# $NetBSD: Makefile,v 1.4 2011/02/04 00:19:51 rmind Exp $
+# $NetBSD: Makefile,v 1.5 2012/01/08 21:34:21 rmind Exp $
 
 PROG=          npfctl
 MAN=           npfctl.8 npf.conf.5
 
-SRCS=          npfctl.c npf_parser.c npf_data.c npf_ncgen.c
+SRCS=          npfctl.c npf_var.c npf_data.c npf_ncgen.c npf_build.c
 
-LDADD+=                -lnpf -lprop
+CPPFLAGS+=     -I${.CURDIR}
+SRCS+=         npf_scan.l npf_parse.y
+YHEADER=       1
+
+LDADD+=                -lnpf -lprop -ly
 DPADD+=                ${LIBNPF} ${LIBPROP}
 
 WARNS?=                4
-NOLINT=                # defined (note: deliberately)
+NOLINT=                # disabled (note: deliberately)
 
 .include <bsd.prog.mk>
diff -r 0b6eadee9cc5 -r dbabed10ac90 usr.sbin/npf/npfctl/npf_build.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/usr.sbin/npf/npfctl/npf_build.c   Sun Jan 08 21:34:21 2012 +0000
@@ -0,0 +1,495 @@
+/*     $NetBSD: npf_build.c,v 1.1 2012/01/08 21:34:21 rmind Exp $      */
+
+/*-
+ * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This material is based upon work partially supported by The
+ * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * npfctl(8) building of the configuration.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: npf_build.c,v 1.1 2012/01/08 21:34:21 rmind Exp $");
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <assert.h>
+#include <err.h>
+
+#include "npfctl.h"
+
+static nl_config_t *           npf_conf = NULL;
+static nl_rule_t *             current_group = NULL;
+static bool                    npf_debug = false;
+static bool                    defgroup_set = false;
+
+void
+npfctl_config_init(bool debug)
+{
+
+       npf_conf = npf_config_create();
+       if (npf_conf == NULL) {
+               errx(EXIT_FAILURE, "npf_config_create failed");
+       }
+       npf_debug = debug;
+}
+
+int
+npfctl_config_send(int fd)
+{
+       int error;
+
+       if (!fd) {
+               _npf_config_setsubmit(npf_conf, "./npf.plist");
+       }
+       if (!defgroup_set) {
+               errx(EXIT_FAILURE, "default group was not defined");
+       }
+       error = npf_config_submit(npf_conf, fd);
+       npf_config_destroy(npf_conf);
+       return error;
+}
+
+int
+npfctl_config_flush(int fd)
+{
+       int ret;
+
+       /* Pass empty configuration to flush. */
+       npfctl_config_init(false);
+       defgroup_set = true;
+       ret = npfctl_config_send(fd);
+       if (ret) {
+               return ret;
+       }
+       return npf_sessions_send(fd, NULL);
+}
+
+bool
+npfctl_table_exists_p(const char *id)
+{
+       return npf_table_exists_p(npf_conf, atoi(id));
+}
+
+static in_port_t *
+npfctl_get_singleport(const npfvar_t *vp)
+{
+       port_range_t *pr;
+
+       if (npfvar_get_count(vp) > 1) {
+               yyerror("multiple ports are not valid");
+       }
+       pr = npfvar_get_data(vp, NPFVAR_PORT_RANGE, 0);
+       if (pr->pr_start != pr->pr_end) {
+               yyerror("port range is not valid");
+       }
+       return &pr->pr_start;
+}
+
+static fam_addr_mask_t *
+npfctl_get_singlefam(const npfvar_t *vp)
+{
+       if (npfvar_get_count(vp) > 1) {
+               yyerror("multiple addresses are not valid");
+       }
+       return npfvar_get_data(vp, NPFVAR_FAM, 0);
+}
+
+static void
+npfctl_build_fam(nc_ctx_t *nc, sa_family_t family,
+    fam_addr_mask_t *fam, int opts)
+{
+       /*
+        * If family is specified, address does not match it and the
+        * address is extracted from the interface, then simply ignore.
+        * Otherwise, address of invalid family was passed manually.
+        */
+       if (family != AF_UNSPEC && family != fam->fam_family) {
+               if (!fam->fam_interface) {
+                       yyerror("specified address is not of the required "
+                           "family %d", family);
+               }
+               return;
+       }
+
+       /*
+        * Optimise 0.0.0.0/0 case to be NOP.  Otherwise, address with
+        * zero mask would never match and therefore is not valid.
+        */
+       if (fam->fam_mask == 0) {
+               npf_addr_t zero;
+               memset(&zero, 0, sizeof(npf_addr_t));
+               if (memcmp(&fam->fam_addr, &zero, sizeof(npf_addr_t))) {
+                       yyerror("filter criterion would never match");
+               }
+               return;
+       }
+
+       switch (fam->fam_family) {
+       case AF_INET:
+               npfctl_gennc_v4cidr(nc, opts,
+                   &fam->fam_addr, fam->fam_mask);
+               break;
+       case AF_INET6:
+               npfctl_gennc_v6cidr(nc, opts,
+                   &fam->fam_addr, fam->fam_mask);
+               break;
+       default:
+               yyerror("family %d is not supported", fam->fam_family);
+       }
+}
+
+static void
+npfctl_build_vars(nc_ctx_t *nc, sa_family_t family, npfvar_t *vars, int opts)
+{
+       const int type = npfvar_get_type(vars);
+       size_t i;
+
+       npfctl_ncgen_group(nc);
+       for (i = 0; i < npfvar_get_count(vars); i++) {
+               void *data = npfvar_get_data(vars, type, i);
+               assert(data != NULL);
+
+               switch (type) {
+               case NPFVAR_FAM: {
+                       fam_addr_mask_t *fam = data;
+                       npfctl_build_fam(nc, family, fam, opts);
+                       break;
+               }
+               case NPFVAR_PORT_RANGE: {
+                       port_range_t *pr = data;
+                       if (opts & NC_MATCH_TCP) {
+                               npfctl_gennc_ports(nc, opts & ~NC_MATCH_UDP,
+                                   pr->pr_start, pr->pr_end);
+                       }
+                       if (opts & NC_MATCH_UDP) {
+                               npfctl_gennc_ports(nc, opts & ~NC_MATCH_TCP,
+                                   pr->pr_start, pr->pr_end);
+                       }
+                       break;
+               }
+               case NPFVAR_TABLE: {
+                       u_int tid = atoi(data);
+                       npfctl_gennc_tbl(nc, opts, tid);
+                       break;
+               }
+               default:
+                       assert(false);
+               }
+       }
+       npfctl_ncgen_endgroup(nc);
+}
+
+static int
+npfctl_build_proto(nc_ctx_t *nc, const opt_proto_t *op)
+{
+       const npfvar_t *popts = op->op_opts;
+       int pflag = 0;
+
+       switch (op->op_proto) {
+       case IPPROTO_TCP:
+               pflag = NC_MATCH_TCP;
+               if (!popts) {
+                       break;
+               }
+               assert(npfvar_get_count(popts) == 2);
+
+               /* Build TCP flags block (optional). */
+               uint8_t *tf, *tf_mask;
+
+               tf = npfvar_get_data(popts, NPFVAR_TCPFLAG, 0);
+               tf_mask = npfvar_get_data(popts, NPFVAR_TCPFLAG, 1);
+               npfctl_gennc_tcpfl(nc, *tf, *tf_mask);
+               break;
+       case IPPROTO_UDP:
+               pflag = NC_MATCH_UDP;
+               break;
+       case IPPROTO_ICMP:
+               /*
+                * Build ICMP block.
+                */
+               assert(npfvar_get_count(popts) == 2);
+
+               int *icmp_type, *icmp_code;
+               icmp_type = npfvar_get_data(popts, NPFVAR_ICMP, 0);
+               icmp_code = npfvar_get_data(popts, NPFVAR_ICMP, 1);
+               npfctl_gennc_icmp(nc, *icmp_type, *icmp_code);
+               break;
+       case -1:
+               pflag = NC_MATCH_TCP | NC_MATCH_UDP;
+               break;
+       default:
+               yyerror("protocol %d is not supported", op->op_proto);
+       }
+       return pflag;
+}
+
+static bool
+npfctl_build_ncode(nl_rule_t *rl, sa_family_t family, const opt_proto_t *op,
+    const filt_opts_t *fopts, bool invert)
+{
+       nc_ctx_t *nc;
+       void *code;
+       size_t len;
+
+       if (family == AF_UNSPEC && op->op_proto == -1 &&
+           op->op_opts == NULL && !fopts->fo_from && !fopts->fo_to &&
+           !fopts->fo_from_port_range && !fopts->fo_to_port_range)
+               return false;
+
+       int srcflag = NC_MATCH_SRC;
+       int dstflag = NC_MATCH_DST;



Home | Main Index | Thread Index | Old Index