From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Lars Ingebrigtsen Newsgroups: gmane.emacs.bugs Subject: bug#36759: 26.1; nftables major mode Date: Wed, 22 Sep 2021 23:16:23 +0200 Message-ID: <87ee9gs448.fsf@gnus.org> References: <87d0i2ecma.fsf@goll.lan> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="29974"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) Cc: Stefan Monnier , 36759@debbugs.gnu.org To: trentbuck@gmail.com (Trent W. Buck) Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Wed Sep 22 23:17:13 2021 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mT9c8-0007YA-IJ for geb-bug-gnu-emacs@m.gmane-mx.org; Wed, 22 Sep 2021 23:17:12 +0200 Original-Received: from localhost ([::1]:41126 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mT9c5-0001tb-SZ for geb-bug-gnu-emacs@m.gmane-mx.org; Wed, 22 Sep 2021 17:17:09 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:54560) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mT9by-0001sH-UA for bug-gnu-emacs@gnu.org; Wed, 22 Sep 2021 17:17:02 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:40351) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mT9by-0005VV-Mk for bug-gnu-emacs@gnu.org; Wed, 22 Sep 2021 17:17:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1mT9by-0005rm-Ad for bug-gnu-emacs@gnu.org; Wed, 22 Sep 2021 17:17:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Wed, 22 Sep 2021 21:17:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 36759 X-GNU-PR-Package: emacs Original-Received: via spool by 36759-submit@debbugs.gnu.org id=B36759.163234539921395 (code B ref 36759); Wed, 22 Sep 2021 21:17:02 +0000 Original-Received: (at 36759) by debbugs.gnu.org; 22 Sep 2021 21:16:39 +0000 Original-Received: from localhost ([127.0.0.1]:51894 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mT9bb-0005Yn-9d for submit@debbugs.gnu.org; Wed, 22 Sep 2021 17:16:39 -0400 Original-Received: from quimby.gnus.org ([95.216.78.240]:34312) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mT9bZ-0005SV-6l for 36759@debbugs.gnu.org; Wed, 22 Sep 2021 17:16:38 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=01TbobSOqw/S7aOFezKC4EqO5JxU7hgWLovUB11XIV4=; b=PFZPdOJDUSBmHsgHHnnmoy0N9E o86xzDZEXHRCQkq47AxlQyQft/8bxzaGDM3Fu0J2/tGcYkJC72+LVAmo1QQRs1jylgN1kbI7BJo8M +k4plgkZEWEmS4Gw9o7pBfMElIrcT0tybJTGPgCvJ6XZIxEMqgOpnh+viVDdkAmXwi9g=; Original-Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mT9bL-0007Nu-Po; Wed, 22 Sep 2021 23:16:28 +0200 X-Now-Playing: Don Armando's 2nd Avenue Band's _Don Armando's 2nd Avenue Band_: "Goin' to a Showdown" In-Reply-To: <87d0i2ecma.fsf@goll.lan> (Trent W. Buck's message of "Mon, 22 Jul 2019 17:45:33 +1000") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:215134 Archived-At: --=-=-= Content-Type: text/plain trentbuck@gmail.com (Trent W. Buck) writes: > I couldn't find a major mode for this, so I wrote a basic one. > This is working well enough for today, but I don't have the time or > interest to maintain it properly. Thanks; seems to work very well. I've included a very lightly edited version of the code below (just adding some of the normal conventions for .el files). I think perhaps this makes more sense in GNU ELPA than in Emacs core (since editing nftables files is a somewhat specialised task), and I looked into putting it there, but I'm still not quite sure how. :-) So I've added Stefan to the CCs -- could you do the right thing here? -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=nftables-mode.el Content-Transfer-Encoding: quoted-printable ;;; nftables-mode.el --- Major mode for editing nftables -*- lexical-bindi= ng: t -*- ;; Copyright (C) 2021 Free Software Foundation, Inc ;; Author: trentbuck@gmail.com (Trent W. Buck) ;; Maintainer: emacs-devel@gnu.org ;; Version: 1.0 ;; Package-Requires: ((emacs "25.1")) ;; Keywords: convenience ;; This package is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; This package is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: (require 'rx) (require 'syntax) ; syntax-ppss, for indentation (defvar nftables-mode-map (make-sparse-keymap)) (defvar nftables-mode-hook nil) (defvar nftables-mode-syntax-table (let ((table (make-syntax-table))) (modify-syntax-entry ?# "<\n" table) ; make #comment work (modify-syntax-entry ?\n ">#" table) ; make #comment work (modify-syntax-entry ?_ "w" table) ; foo_bar is 1 word (not 2) table)) ;;; NOTE: I started with the keywords in the nano highlighter, but ;;; they were really incomplete. So instead I looked at the ;;; flex/bison rules in the nft source code (as at debian/0.9.1-2-2-g3255aa= a): ;;; https://salsa.debian.org/pkg-netfilter-team/pkg-nftables/blob/maste= r/src/scanner.l ;;; https://salsa.debian.org/pkg-netfilter-team/pkg-nftables/blob/maste= r/src/parser_bison.y ;;; NOTE: not supporting multi-statement lines "list ruleset; flush ruleset= ". ;;; NOTE: not supporting multi-line statements "list \\\n ruleset". ;;; NOTE: not supporting arbitrary whitespace in some places. ;;; NOTE: identifiers are hard (e.g. bare addresses, names, quoted strings)= , so ;;; not supporting all those properly. ;;; NOTE: family can be omitted; it defaults to "ip" (IPv4 only). ;;; I am not supporting that, because you USUALLY want "inet" (IPv4/I= Pv6 dual-stack). ;;; NOTE: there are two main styles, I'm supporting only those and not a mi= x of same. ;;; ;;; Style #1: ;;; ;;; flush ruleset ;;; table inet foo { ;;; chain bar { ;;; type filter hook input priority filter ;;; policy drop ;;; predicate [counter] [log] ;;; } ;;; } ;;; ;;; Style #2 (everything at the "top level"): ;;; ;;; flush ruleset ;;; add table inet foo ;;; add chain inet foo bar { type filter hook input priority fil= ter; policy drop } ;;; add rule inet foo bar predicate [counter] [log] (defvar nftables-font-lock-keywords `(;; include "foo" ;; list ruleset ;; flush ruleset (,(rx bol (or "include" "list ruleset" "flush ruleset" "list tables" "list counters" "list quotas") eow) . font-lock-preprocessor-face) ;; define foo =3D bar ;; define foo =3D { bar, baz } ;; redefine foo =3D bar ;; undefine foo (,(rx bol (group (or "define" "redefine" "undefine")) " " (group (one-or-more (any alnum ?_))) eow) (1 font-lock-type-face) (2 font-lock-variable-name-face)) ;; add table inet my_table { ... } ;; table inet my_table { ... } (,(rx bol (group (or "table" ; style #1 "add table")) ; style #2 " " ;; This is parser_bison.y:family_spec (group (or "ip" "ip6" "inet" "arp" "bridge" "netdev")) " " (group (one-or-more (any alnum ?_))) eow) (1 font-lock-type-face) (2 font-lock-constant-face) (3 font-lock-variable-name-face)) ;; chain my_chain { ;; set my_set { ;; map my_map { (,(rx bol (one-or-more blank) (group (or "chain" "set" "map")) " " (group (one-or-more (any alnum ?_)))) (1 font-lock-type-face) (2 font-lock-variable-name-face)) ;; add chain inet my_table my_chain { ... } ;; add set inet my_table my_set { ... } ;; add map inet my_table my_map { ... } ;; add rule inet my_table my_chain ... ;; add element inet my_table my_set { ... } ;; add element inet my_table my_map { ... } (,(rx bol (group "add " (or "chain" "set" "map" "rule" "element")) " " (group (or "ip" "ip6" "inet" "arp" "bridge" "netdev")) " " (group (one-or-more (any alnum ?_))) " " (group (one-or-more (any alnum ?_))) eow) (1 font-lock-type-face) (2 font-lock-constant-face) (3 font-lock-variable-name-face) (4 font-lock-variable-name-face)) ;; Remaining rules not anchored at beginning-of-line. ;; << chain specification >> ;; { type filter hook input priority filter; } (,(rx bow (group "type") " " (group (or "filter" "nat" "route")) " " (group "hook") " " (group (or "prerouting" "input" "forward" "output" "postrouting" "ingress" "dormant")) " " (group "priority") " " (group (or (and (opt "-") (one-or-more digit)) "raw" "mangle" "dstnat" "filter" "security" "srcnat" "dstnat" "filter" "out" "srcnat")) eow) (1 font-lock-type-face) (3 font-lock-type-face) (5 font-lock-type-face) (2 font-lock-constant-face) (4 font-lock-constant-face) (6 font-lock-constant-face)) ;; << Table 8. Set specifications >> ;; type x # set ;; type x : y # map ;; flags x , y , z # set/map ;; timeout 60s # set ;; gc-interval 12s # set ;; elements =3D { ... } # set/map ;; size 1000 # set/map ;; auto-merge # set (,(rx bow (group "type") " " (group (or "ipv4_addr" "ipv6_addr" "ether_addr" "inet_proto" "ine= t_service" "mark")) (optional " : " (group (or "ipv4_addr" "ipv6_addr" "ether_addr" "inet_proto" "in= et_service" "mark" "counter" "quota"))) eow) (1 font-lock-type-face) (2 font-lock-constant-face)) (,(rx bow (group "flags") " " (group (or "constant" "dynamic" "interval" "timeout") (zero-or-more ", " (or "constant" "dynamic" "interval" "timeout"))) eow) (1 font-lock-type-face) (2 font-lock-constant-face)) (,(rx bow (group (or "timeout" "gc-interval")) " " (group ; copied from scanner.l (optional (one-or-more digit) "d") (optional (one-or-more digit) "h") (optional (one-or-more digit) "m") (optional (one-or-more digit) "s") (optional (one-or-more digit) "ms")) eow) (1 font-lock-type-face) (2 font-lock-string-face)) (,(rx bow (group "size") " " (group (one-or-more digit)) eow) (1 font-lock-type-face) (2 font-lock-string-face)) (,(rx bow "auto-merge" eow) . font-lock-type-face) (,(rx bow (group "elements") " =3D " eow) (1 font-lock-type-face)) ;; policy accept ;; policy drop (,(rx (group "policy") " " (group (or "accept" "drop"))) (1 font-lock-type-face) (2 font-lock-function-name-face)) ;; $variable ;; @array (,(rx (or "@" "$") alpha (zero-or-more (any alnum ?_))) . font-lock-variable-name-face) ;; Simplified because scanner.l is INSANE for IPv6. ;; 1234 (e.g. port number) ;; 1.2.3.4 ;; ::1 (,(rx bow (or ;; IPv4 address (optional CIDR) (and digit (zero-or-more (any digit ".")) digit (optional "/" (one-or-more digit))) ;; IPv6 address (optional CIDR) ;; Oops, this was matching "add"! ;; WOW THIS IS REALLY REALLY HARD! (and (zero-or-more (or (and (repeat 1 4 hex-digit) ":") "::")) (repeat 1 4 hex-digit) (optional "/" (one-or-more digit))) ;; Bare digits. ;; Has to be after IPv4 address, or IPv4 address loses. ;; (or (one-or-more digit)) ) eow) . font-lock-string-face) ;; parser_bison.y:family_spec_explicit ;; (,(rx bow (or "ip" "ip6" "inet" "arp" "bridge" "netdev") eow) ;; . font-lock-constant-face) ;; parser_bison.y:verdict_expr (,(rx bow (or "accept" "drop" "continue" "return") eow) . font-lock-function-name-face) (,(rx bow (group (or "jump" "goto")) " " (group (one-or-more (any alnum ?_)))) ; chain_expr (1 font-lock-function-name-face) (2 font-lock-variable-name-face)))) ;;; Based on equivalent for other editors: ;;; * /usr/share/nano/nftables.nanorc ;;; * https://github.com/nfnty/vim-nftables ;;;###autoload (define-derived-mode nftables-mode prog-mode "nft" "Major mode to edit nftables files." (setq-local comment-start "#") (setq-local font-lock-defaults `(nftables-font-lock-keywords nil nil)) ;; ;; make "table my_table {" result in indents on the next line. ;; (setq-local electric-indent-chars ?\}) (setq-local indent-line-function #'nftables-indent-line) (setq-local tab-width 4)) ;;; Stolen from parsnip's (bradyt's) dart-mode. ;;; https://github.com/bradyt/dart-mode/blob/199709f7/dart-mode.el#L315 (defun nftables-indent-line () (let (old-point) (save-excursion (back-to-indentation) (let ((depth (car (syntax-ppss)))) (when (=3D ?\) (char-syntax (char-after))) (setq depth (1- depth))) (indent-line-to (* depth tab-width))) (setq old-point (point))) (when (< (point) old-point) (back-to-indentation)))) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.nft\\(?:ables\\)?\\'" . nftables-mode)) ;;;###autoload (add-to-list 'auto-mode-alist '("/etc/nftables.conf" . nftables-mode)) ;;;###autoload (add-to-list 'interpreter-mode-alist '("nft\\(?:ables\\)?" . nftables-mode)) (provide 'nftables-mode) ;;; nftables-mode.el enads here. --=-=-=--