Difference between pages "The Gentoo.org Redesign, Part 2" and "Package:Nftables"

From Funtoo
(Difference between pages)
Jump to navigation Jump to search
 
 
Line 1: Line 1:
{{Article
{{Ebuild
|Summary=Have you ever woken up in the morning to the realization that your personal development Web site isn't really that great? If so, you're in good company. In this series, Daniel Robbins shares his experiences as he redesigns the www.gentoo.org Web site using technologies like XML, XSLT, and Python. Along the way, you may find some excellent approaches to use in your next Web site redesign. In this, the second installment, Daniel shows off the new documentation system and sets up a daily CVS-log mailing list.
|Summary=Linux kernel (3.13+) firewall, NAT and packet mangling tools
|Author=Drobbins
|CatPkg=net-firewall/nftables
|Previous in Series=The Gentoo.org Redesign, Part 1
|Repository=Gentoo Portage Tree
|Next in Series=The Gentoo.org Redesign, Part 3
}}
}}
== The doc system ==
=== What is nftables? ===
'''nftables''' is the successor to [[iptables]]. It replaces the existing iptables, ip6tables, arptables and ebtables framework. It uses the Linux kernel and a new userspace utility called nft. nftables provides a compatibility layer for the ip(6)tables and framework.


If you've read the first installment of my series on the gentoo.org redesign, then you know that I'm the Chief Architect of Gentoo Linux, making me responsible for the Gentoo Linux Web site. And right now, the site leaves a lot to be desired. Yes, it does look somewhat attractive, but when you look beyond the cute graphics you will see that it really doesn't serve the needs of its primary target audience: Gentoo Linux developers, users, and potential users.
==Introduction==
As with the iptables framework, nftables is build upon rules which specify the actions. These rules are attached to chains. A chain can contain a collection of rules and is registered into the netfilter hooks. Chains are stored inside tables. A table is specific for one of the layer 3 protocols. One of the main differences with iptables is that there are no predefined tables and chains anymore.


Last time, I used a user-centric design approach to create a set of priorities for the site, and then used these priorities to create an action plan for revamping gentoo.org. Two things were at the top of the priority list: new developer documentation and a new mailing list to communicate to developers changes made to our CVS repository. While adding the new CVS mailing list was relatively easy (though, as you will see, it was more difficult than I thought), the new developer documentation required a lot of planning and work.
===Tables===
A table is nothing more than a container for your chains. With nftables there are no predefined tables (filter, raw, mangle...) anymore. You are free to recreate the iptables-like structure, but anything might do.
Currently there are 5 different families of tables:
* '''ip''': Used for IPv4 related chains;
* '''ip6''': Used for IPv6 related chains;
* '''arp''': Used for ARP related chains;
* '''bridge''': Used for bridging related chains;
* '''inet''': Mixed ipv4/ipv6 chains (kernel 3.14 and up).


Not only did I need to create some actual documentation (a task that I had been ignoring for too long), but I also had to choose an official XML syntax that our new master documentation would use. You see, until a few weeks ago, I was creating the documentation in raw HTML. This was definitely a naughty thing to do, because by doing this content was being mixed (the actual information) with presentation (the display-related HTML tags). And what did I end up with? An inflexible mess, that's what. It was hard to edit the actual documentation and extremely difficult to make site-wide HTML improvements.
It is not hard to recognize the old tables framework in these tables. The only new one is the inet table which is used for both IPv4 and IPv6 traffic. It should make firewalling for dual-stack hosts easier by combining the rules for IPv4 and IPv6.


In this article, I'll proudly demonstrate the site's new flexible XML documentation solution. But first, I'll recap my experiences in adding the CVS log mailing list to our site.
===Chains===
Chains are used to group together rules. As with the tables, nftables does not have any predefined chains. Chains are grouped in base and non-base types. Base chains are registered in one of the netfilter hooks. A base chain has a hook its registered with, a type and a priority.  Non-base chains are not attached to a hook and they don't see any traffic by default. They can be used to arrange a rule-set in a tree of chains.
There are currently three types of chains:
* '''filter''': for filtering packets
* '''route''': for rerouting packets
* '''nat''': for performing Network Address Translation. Only the first packet of a flow hits this chain, making it impossible to use it for filtering.
The hooks that can be used are:
* '''prerouting''': This is before the routing decision, all packets entering the machine hits this chain
* '''input''': All packets for the local system hits this hook
* '''forward''': Packets not for the local system, those that need to be forwarded hits this hook
* '''output''': Packets that originate from the local system pass this hook
* '''postrouting''': This hook is after the routing decision, all packets leaving the machine hits this chain
{{Note|The ARP address family only supports the input and output hook}}
{{Note|The bridge address family only seems to supports the input, forward and output hook}}


== Adding the CVS log mailing list ==
====Priorities====


The goal of the CVS log mailing list is to inform developers of new commits made to our CVS repository. Since I already had the mailman mailing list manager (see Resources) installed, I thought that creating this new list would be easy. First, I would simply create the mailing list, then add the proper "hook" to the CVS repository so that e-mails would be automatically generated and sent out, describing the changes to our sources as they happened.
{{Note|Priorities do not currently appear to have any effect on which chain sees packets first.}}


I first started researching a special file in my repository's CVSROOT called "loginfo." Theoretically, by modifying this file, I could instruct CVS to execute a script when any commit (and thus, modification) was made to the repository. So I created a special loginfo script and plugged it into my existing repository. And it did indeed send out e-mails to the new "gentoo-cvs" mailing list whenever modifications were made to our sources.
{{Note|Since the priority seems to be an unsigned integer, negative priorities will be converted into very high priorities.}}


Unfortunately, this solution wasn't all I'd hoped it would be. First of all, it generated lots of e-mail messages -- one for each modified file -- and secondly, the messages were cryptic and sometimes even empty! I quickly removed my loginfo script and put the gentoo-cvs mailing list project on hold. It was clear that CVS's loginfo hook wasn't appropriate for my needs, and I had a hard time tracking down any loginfo-related documentation that could help me solve my problem.
===Rules===
Rules specify which action has to be taken for which packets. Rules are attached to chains. Each rule can has an expression to match packets with and one or multiple actions when matching. Main differences with iptables is that it is possible to specify multiple actions and that by default counters are off. It must be specified explicitly in rules if you want packet- and byte-counters for a rule.
Each rule has a unique handle number by which it can be distinguished.
The following matches are available:
* '''ip''': IP protocol
* '''ip6''': IPv6 protocol
* '''tcp''': TCP protocol
* '''udp''': UDP protocol
* '''udplite''': UDP-lite protocol
* '''sctp''': SCTP protocol
* '''dccp''': DCCP protocol
* '''ah''': Authentication headers
* '''esp''': Encrypted security payload headers
* '''ipcomp''': IPcomp headers
* '''icmp''': icmp protocol
* '''icmpv6''': icmpv6 protocol
* '''ct''': Connection tracking
* '''meta''': meta properties such as interfaces


== cvs2cl.pl ==
====Matches====
{|class=wikitable
| Match
| Arguments
| Description/Example
|-
| rowspan="11" | '''ip'''
| version
| Ip Header version
|-
| hdrlength
| IP header length
|-
| tos
|Type of Service
|-
| length
| Total packet length
|-
| id
| IP ID
|-
| frag-off
| Fragmentation offset
|-
| ttl
| Time to live
|-
| protocol
| Upper layer protocol
|-
| checksum
| IP header checksum
|-
| saddr
| Source address
|-
| daddr
| Destination address
|-
| rowspan="8" | '''ip6'''
| version
| IP header version
|-
| priority
|
|-
| flowlabel
| Flow label
|-
| length
| Payload length
|-
| nexthdr
| Next header type (Upper layer protocol number)
|-
| hoplimit
| Hop limit
|-
|saddr
| Source Address
|-
|daddr
| Destination Address
|-
| rowspan="9" | '''tcp'''
| sport
| Source port
|-
| dport
| Destination port
|-
| sequence
| Sequence number
|-
| ackseq
| Acknowledgement number
|-
| doff
| Data offset
|-
| flags
| TCP flags
|-
| window
| Window
|-
| checksum
| Checksum
|-
| urgptr
| Urgent pointer
|-
| rowspan="4" | '''udp'''
| sport
| Source port
|-
| dport
| destination port
|-
| length
| Total packet length
|-
| checksum
| Checksum
|-
| rowspan="4" | '''udplite'''
| sport
| Source port
|-
| dport
| destination port
|-
| cscov
| Checksum coverage
|-
| checksum
| Checksum
|-
| rowspan="4" |'''sctp'''
| sport
| Source port
|-
| dport
| destination port
|-
|vtag
|Verification tag
|-
| checksum
| Checksum
|-
| rowspan="2" |'''dccp'''
| sport
| Source port
|-
| dport
| destination port
|-
| rowspan="4" |'''ah'''
| nexthdr
| Next header protocol (Upper layer protocol)
|-
| hdrlength
| AH header length
|-
| spi
| Security Parameter Index
|-
| sequence
| Sequence Number
|-
| rowspan="2" | '''esp'''
| spi
| Security Parameter Index
|-
| sequence
| Sequence Number
|-
| rowspan="3" | '''ipcomp'''
| nexthdr
| Next header protocol (Upper layer protocol)
|-
| flags
| Flags
|-
| cfi
| Compression Parameter Index
|-
| '''icmp'''
| type
| icmp packet type
|-
| '''icmpv6'''
| type
| icmpv6 packet type
|-
|rowspan="12"|'''ct'''
|state
|State of the connection
|-
|direction
|Direction of the packet relative to the connection
|-
|status
|Status of the connection
|-
|mark
|Connection mark
|-
|expiration
|Connection expiration time
|-
|helper
|Helper associated with the connection
|-
|l3proto
|Layer 3 protocol of the connection
|-
|saddr
|Source address of the connection for the given direction
|-
|daddr
|Destination address of the connection for the given direction
|-
|protocol
|Layer 4 protocol of the connection for the given direction
|-
|proto-src
|Layer 4 protocol source for the given direction
|-
|proto-dst
|Layer 4 protocol destination for the given direction
|-
| rowspan="13" | '''meta'''
| length
| Length of the packet in bytes: ''meta length > 1000''
|-
| protocol
| ethertype protocol: ''meta protocol vlan''
|-
| priority
| TC packet priority
|-
| mark
| Packet mark
|-
| iif
| Input interface index
|-
| iifname
| Input interface name
|-
| iiftype
| Input interface type
|-
| oif
| Output interface index
|-
| oifname
| Output interface name
|-
| oiftype
| Output interface hardware type
|-
| skuid
| UID associated with originating socket
|-
| skgid
| GID associated with originating socket
|-
| rtclassid
| Routing realm
|-
|}
====Statements====
Statements represent the action to be performed when the rule matches. They exist in two kinds: Terminal statements, unconditionally terminate the evaluation of the current rules and non-terminal statements that either conditionally or never terminate the current rules. There can be an arbitrary amount of non-terminal statements, but there must be only a single terminal statement.
The terminal statements can be:
* '''accept''': Accept the packet and stop the ruleset evaluation.
* '''drop''': Drop the packet and stop the ruleset evaluation.
* '''reject''': Reject the packet with an icmp message
* '''queue''': Queue the packet to userspace and stop the ruleset evaluation.
* '''continue''':
* '''return''': Return from the current chain and continue at the next rule of the last chain. In a base chain it is equivalent to accept
* '''jump <chain>''': Continue at the first rule of <chain>. It will continue at the next rule after a return statement is issued
* '''goto <chain>''': Similar to jump, but after the new chain the evaluation will continue at the last chain instead of the one containing the goto statement


Several weeks later I started looking for an alternative to loginfo. This time I did the smart thing and headed over to http://freshmeat.net. There I quickly found just what I was looking for: the incredibly wonderful cvs2cl.pl perl script available from http://red-bean.com (see Resources). Instead of using the loginfo hook, cvs2cl.pl uses the cvs log command to connect directly to the repository and extract the appropriate relevant log information. Also, rather than spitting out relatively cryptic CVS log messages, it does a great job of reformatting everything into a readable ChangeLog format:
== Installing nftables ==
=== Kernel ===
These kernel options must be set {{kernelop|title=Network support|desc= Networking options
        [*] Network packet filtering framework (Netfilter)  --->
            Core Netfilter Configuration  --->
                <M> Netfilter nf_tables support
                <M>  Netfilter nf_tables IPv6 exthdr module
                <M>  Netfilter nf_tables meta module
                <M>  Netfilter nf_tables conntrack module
                <M>  Netfilter nf_tables rbtree set module
                <M>  Netfilter nf_tables hash set module
                <M>  Netfilter nf_tables counter module
                <M>  Netfilter nf_tables log module
                <M>  Netfilter nf_tables limit module
                <M>  Netfilter nf_tables nat module
                <M>  Netfilter x_tables over nf_tables module
            IP: Netfilter Configuration  --->
                <M> IPv4 nf_tables support
                <M>  nf_tables IPv4 reject support
                <M>  IPv4 nf_tables route chain support
                <M>  IPv4 nf_tables nat chain support
            IPv6: Netfilter Configuration  --->
                <M> IPv6 nf_tables support
                <M>  IPv6 nf_tables route chain support
                <M>  IPv6 nf_tables nat chain support
            <M>  Ethernet Bridge nf_tables support
}}
 
=== Emerging ===
To install nftables, run the following command:
<console>
###i## emerge net-firewall/nftables
</console>
 
 
== OpenRC configuration ==
Don't forget to add nftables service to startup:
<console>
###i## rc-update add nftables default
</console>
 
You cannot use iptables and nft to perform NAT at the same time. So make sure that the iptable_nat module is unloaded. Remove iptables_nat module:
<console>
###i## rmmod iptable_nat
</console>
 
Start nftables:
<console>
###i## /etc/init.d/nftables start
</console>
 
 
== Using nftables ==
All nftable commands are done with the nft ultility from {{Package|net-firewall/nftables}}.
===Tables===
====Creating tables====
The following command adds a table called filter for the ip(v4) layer
<console>
###i## nft add table ip filter
</console>
Likewise a table for arp can be created with
<console>
###i## nft add table arp filter
</console>
{{Note|The name "filter" used here is completly arbitrary. It could have any name}}
====Listing tables====
The following command lists all tables for the ip(v4) layer
<console>
###i## nft list tables ip
</console>
<pre>
table filter
</pre>
The contents of the table filter can be listed with:
<console>
###i## nft list table ip filter
</console>
<pre>
table ip filter {
        chain input {
                type filter hook input priority 0;
                ct state established,related accept
                iifname "lo" accept
                ip protocol icmp accept
                drop
        }
}
</pre>
using -a with the nft command, it shows the handle of each rule. Handles are used for various operations on specific rules:
<console>
###i## nft -a list table ip filter
</console>
<pre>
table ip filter {
        chain input {
                type filter hook input priority 0;
                ct state established,related accept # handle 2
                iifname "lo" accept # handle 3
                ip protocol icmp accept # handle 4
                drop # handle 5
        }
}
</pre>
 
====Deleting tables====
The following command deletes the table called filter for the ip(v4) layer:
<console>
###i## nft delete table ip filter
</console>
===chains===
====Adding chains====
The following command adds a chain called input to the ip filter table and registered to the input hook with priority 0. It is of the type filter.
<console>
###i## nft add chain ip filter input { type filter hook input priority 0 \; }
</console>
{{Note|If You're running this command from Bash you need to escape the semicolon}}
A non-base chain can be added by not specifying the chain configurations between the curly braces.
 
====Removing chains====
The following command deletes the chain called input
<console>
###i## nft delete chain ip filter input
</console>
{{Note|Chains can only be deleted if there are no rules in them.}}
===rules===
====Adding rules====
The following command adds a rule to the chain called input, on the ip filter table, dropping all traffic to port 80:
<console>
###i## nft add rule ip filter input tcp dport 80 drop
</console>
====Deleting Rules====
To delete a rule, you first need to get the handle number of the rule. This can be done by using the -a flag on nft:
<console>
###i## nft  rule ip filter input tcp dport 80 drop
</console>
<pre>
table ip filter {
        chain input {
                type filter hook input priority 0;
                tcp dport http drop # handle 2
        }
}
</pre>
It is then possible to delete the rule with:
<console>
###i## nft delete rule ip filter input handle 2
</console>
== Management ==
=== Backup ===
You can also backup your rules:
<console>
###i## echo "nft flush ruleset" > backup.nft
</console>


{{file|desc=Output generated by cvs2cl.pl|body=
<console>
2001-04-09 20:58  drobbins
###i## nft list ruleset >> backup.nft
      * app-doc/gentoo-web/files/xml/dev.xml: new fixes
</console>
2001-04-09 20:47  drobbins
 
      * app-doc/gentoo-web/: gentoo-web-1.0.ebuild,
=== Restoration ===
      files/pyhtml/index.pyhtml, files/xml/gentoo-howto.xml: new gentoo-howto
And load it atomically:
      fixes
<console>
2001-04-09 20:03  drobbins
###i## nft -f backup.nft
      * app-doc/gentoo-web/files/xml/dev.xml: typo fix
</console>
2001-04-09 20:02  drobbins
 
       * app-doc/gentoo-web/files/pyhtml/index.pyhtml: little update
== OpenRC configuration ==
}}
 
Don't forget to add nftables service to startup:
<console>
###i## rc-update add nftables default
</console>
== Init script (firewall nftables like a iptables) ==
<pre>
#!/sbin/runscript
#      Raphael Bastos aka coffnix        #
#      Init Script for Funtoo Linux      #
##########################################
 
depend() {
        need net
        need nftables
        }
 
start(){
##################### PARTE 1 #####################
ebegin "Starting Firewall NFTables"
 
#######################################################################
### Incompatibilities ###
# You cannot use iptables and nft to perform NAT at the same time.
# So make sure that the iptable_nat module is unloaded
rmmod iptable_nat
 
#######################################################################
 
echo 1 > /proc/sys/net/ipv4/ip_forward
echo 1 > /proc/sys/net/ipv4/ip_dynaddr
echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
for f in /proc/sys/net/ipv4/conf/*/rp_filter ; do echo 1 > $f ; done
 
#######################################################################
 
iptables -t nat -F
 
#######################################################################
 
# ipv4
nft -f /etc/nftables/ipv4-filter
 
# ipv4 nat
nft -f /etc/nftables/ipv4-nat
 
# ipv6
nft -f /etc/nftables/ipv6-filter
 
# Rules firewall NTFtables
nft -f /etc/nftables/firewall.rules
 
#######################################################################
 
}
 
stop(){
ebegin "Stoping Firewall NFTables"
 
#######################################################################
 
#iptables -t nat -F
NFT=nft
FAMILIES="ip ip6 arp bridge"
 
for FAMILY in $FAMILIES; do
  TABLES=$($NFT list tables $FAMILY | grep "^table\s" | cut -d' ' -f2)
 
  for TABLE in $TABLES; do
    CHAINS=$($NFT list table $FAMILY $TABLE | grep "^\schain\s" | cut -d' ' -f2)
 
    for CHAIN in $CHAINS; do
       echo "Flushing chain: $FAMILY->$TABLE->$CHAIN"
      $NFT flush chain $FAMILY $TABLE $CHAIN
      $NFT delete chain $FAMILY $TABLE $CHAIN
    done


cvs2cl.pl can also be instructed to generate output in XML format, and in my next article I'll take advantage of this by incorporating an up-to-date ChangeLog into the new developer section of our site.
    echo "Flushing table: $FAMILY->$TABLE"
    $NFT flush table $FAMILY $TABLE
    $NFT delete table $FAMILY $TABLE
  done
done
}


== The cvslog.sh script ==
status(){
nft list ruleset
}


Here's the script I now use to generate the daily ChangeLog e-mails. First, it changes the current working directory to the location of my checked-out CVS repository. Then, it creates $yesterday and $today environment variables that contain the appropriate dates in RFC 822 format. Notice that both date variables have the time set to either "00:00" or midnight. These variables are, in turn, used to create a $cvsdate variable that is then passed to cvs2cl.pl to specify the date range that I'm interested in -- the span of time from yesterday at midnight to today at midnight. Thus, the $cvsdate variable contains a datespec that informs cvs2cl.pl to log only changes made yesterday, but not others.
# End
</pre>


In addition, I also created a $nicedate variable (used in the mail subject line) and use the mutt mailer (in mailx compatibility mode [see Resources]) to send the e-mail to the gentoo-cvs mailing list:
=== Personal Rules ===
And configure your personal rules:
<pre>
# A simple firewall
#


{{file|name=cvslog.sh|body=
table ip filter {
#!/bin/bash
        chain input {
cd /usr/portage
                type filter hook input priority 0;
cvs -q update -dP
                ct state established,related accept
yesterday=`date -d "1 day ago 00:00" -R`
today=`date -d "00:00" -R`
cvsdate=-d\'${yesterday}\<${today}\'
nicedate=`date -d yesterday +"%d %b %Y %Z (%z)"`
/home/drobbins/gentoo/cvs2cl.pl -f /home/drobbins/gentoo/cvslog.txt -l "${cvsdate}"
mutt -x gentoo-cvs -s "cvs log for $nicedate" <\
/home/drobbins/gentoo/cvslog.txt
}}


Using cron, I run this script every night at midnight. Thanks to cvs2cl.pl, my developers now get accurate and readable daily CVS updates.
                # invalid connections
                ct state invalid drop


== The documentation project ==
                # loopback interface
                iifname "lo" accept


Now, for the Gentoo Linux documentation project. Our new documentation system involves two groups of people or target audiences: the documentation creators and the documentation readers. The creators need a well-designed XML syntax that doesn't get in their way; the readers, who couldn't care less about the XML, want generated HTML documentation that is both functional and attractive. The implementation challenge is to put together a complete system that addresses the needs of both audiences. Oh, and I suppose there is a third "audience" -- me, the webmaster and the person designing the new system. Since I'm going to be interacting with the new doc system whenever the site is upgraded, I need it to be reliable and flexible.
                # icmp
                ip protocol icmp accept


== The Web-ready HTML ==
                # open ports
                #tcp dport {ssh, http} accept
                #udp dport {5060} accept
                #udp dport {4000-20000} accept


First, let's talk a bit about the Web-ready HTML that'll be generated from my master XML files. To make great, readable documentation, I'll need to have support for the proper XML tags. For example, the ability to insert notes, important messages, and warnings into the body of the document (and have them prominently displayed in the resultant HTML) is a must. Also, I must be able to insert blocks of code, and it would be great if actual user input could somehow be offset from program output. I could even add tags that highlight the source code comments in an alternate color so that the code blocks are more readable.
                # Bind DNS Server
                udp sport domain accept
                tcp sport domain accept


The documents should have a table of contents (with hyperlinks to the appropriate chapters), a synopsis, a revision date, version, and an authors list at the top of the document. And, of course, every document should have a header at the extreme top of the page containing a small Gentoo Linux logo. Clicking on this logo should bring you back to the main Gentoo Linux page. Last but not least, every document should have a footer that contains copyright information, along with a contact e-mail address.


== The spiffy new logo ==
                # LAN
                #ip saddr 192.168.100.0/24 ct state new counter accept


This was a hefty list of requirements, and I decided to focus on the most entertaining part first, the new Gentoo Linux logo that would appear in the upper-left corner of every Gentoo Linux document. I used the "g" from the "gentoo" graphic (created using the excellent and free Blender 3D program) on our main page as the basis for the new smaller logo. I tweaked the extrusion settings a bit and then added a chrome environment map. Finally, I positioned the lights and camera just so, and the new logo was complete. After importing it into Xara X (see Resources) and adding some text, this was the result:
                # everything else
                drop
        }
        chain forward {
                #ip daddr 192.168.100.0/24 accept
        }
}


[[File:L-redesign-02.gif|frame|class=img-responsive|caption=The new Gentoo Linux logo]]


I used this new logo as inspiration for the rest of the HTML color scheme, using a purplish theme throughout. I made heavy use of cascading style sheets (CSS) to control font attributes and spacing. Once I had a decent HTML prototype in place, I started focusing on the guts of the new documentation -- the new XML syntax. I wanted the syntax to be as simple as possible, so I created just enough XML tags to allow for the proper organization of the document, but no more. Then I started working on the XSLT to transform the XML into the target HTML.
table ip6 filter {
        chain input {
                type filter hook input priority 0;


== The result! ==
                # established/related connections
                ct state established,related accept


After much tweaking and a good amount of feedback from one of my developers, the new documentation system reached the point where it was ready for use. I immediately began work on our first new development guide, "The Gentoo Linux Documentation Guide" (xml-guide.html), which contains a complete description of the new XML format. Not only did this allow other developers to begin work on the new-style documentation, but it also served as an excellent example of the new documentation system in action. Be sure to read this guide to get a complete understanding of our new XML syntax.
                # invalid connections
                ct state invalid drop


== DocBook vs. Guide ==
                # loopback interface
                iifname lo accept


If you're working on your own documentation solution, you may also want to consider the DocBook XML and SGML formats (see Resources). DocBook is well-suited for large-scale technical documentation and book projects, is very flexible, and has many (maybe too many) features. In addition, there are a number of existing packages that can be used to convert DocBook XML/SGML to man pages, texinfo files, Postscript, PDF, and, of course, HTML formats.
                # icmp
                ip6 nexthdr icmpv6 accept


I didn't choose DocBook because a lightweight XML syntax worked best for Gentoo's needs. Right now, our XML guide syntax has around 20 tags and about 10 attributes. The limited tagset makes guide XML easy to transform into other formats such as HTML, and also ensures a certain level of consistency throughout our entire documentation set, since the format is so simple. Because I have my own XML format, I'll be able to extend the format with new tags as needed. I like having that level of control. I view XML as a technology that should be used by people to structure their data in ways that they find most helpful. In other words, the ability to define our own elements and attributes is a precious thing, and I should take full advantage of it. After all, it's the defining feature of XML.
                # open tcp ports: sshd (22), httpd (80)
                #tcp dport {ssh, http} accept
                #udp dport {5060} accept
                #udp dport {4000-20000} accept


Of course, creating your own XML syntax is not always the best solution, especially when data interchange is important to you. Amid all the XML hype, one thing that is often overlooked is that conversion to and from different XML formats can be extremely difficult. In many cases, the two formats won't be 100% compatible, and you'll have the unpleasant choice of either throwing away data and/or metadata, intentionally avoiding use of certain elements or attributes, or creating a "super-format" that will accommodate the data and metadata from both XML formats. In the documentation world, DocBook is a pretty good choice as a "super-format" because it's so flexible; it can easily accommodate documentation imported from a variety of sources.
                # everything else
                drop
        }
}


However, DocBook's richness and flexibility can also create problems. For example, there may be hundreds of tags that you may never need, and supporting all these tags in your XSLT can make conversion to other formats more difficult. So, while DocBook is a great container for documentation converted from other formats, your own minimal XML syntax will almost always be easier to convert to other formats.


The most important thing is to carefully evaluate any potential solution while keeping the needs of your target audience(s) in mind.
table ip nat {
        chain prerouting {
                #tcp dport 8081 ip protocol tcp counter dnat 192.168.100.24
        }
        chain postrouting {
                #masquerade random,persistent
                #ip saddr 192.168.100.0/24 oif eth0 snat 192.168.25.3
        }


== Wrapping it up ==
}
</pre>


With the new doc system in place, I converted all our docs to the new format and posted the new docs on our existing site. In addition, I created a link to the gentoo-cvs mailing list subscription page. The key point here is that I integrated these features into the existing site so that users could benefit from the improvements right away.
[[Category:System]]
{{ArticleFooter}}
[[Category:First Steps]]
{{EbuildFooter}}

Revision as of 19:44, February 22, 2015

Nftables

   Tip

We welcome improvements to this page. To edit this page, Create a Funtoo account. Then log in and then click here to edit this page. See our editing guidelines to becoming a wiki-editing pro.

What is nftables?

nftables is the successor to iptables. It replaces the existing iptables, ip6tables, arptables and ebtables framework. It uses the Linux kernel and a new userspace utility called nft. nftables provides a compatibility layer for the ip(6)tables and framework.

Introduction

As with the iptables framework, nftables is build upon rules which specify the actions. These rules are attached to chains. A chain can contain a collection of rules and is registered into the netfilter hooks. Chains are stored inside tables. A table is specific for one of the layer 3 protocols. One of the main differences with iptables is that there are no predefined tables and chains anymore.

Tables

A table is nothing more than a container for your chains. With nftables there are no predefined tables (filter, raw, mangle...) anymore. You are free to recreate the iptables-like structure, but anything might do. Currently there are 5 different families of tables:

  • ip: Used for IPv4 related chains;
  • ip6: Used for IPv6 related chains;
  • arp: Used for ARP related chains;
  • bridge: Used for bridging related chains;
  • inet: Mixed ipv4/ipv6 chains (kernel 3.14 and up).

It is not hard to recognize the old tables framework in these tables. The only new one is the inet table which is used for both IPv4 and IPv6 traffic. It should make firewalling for dual-stack hosts easier by combining the rules for IPv4 and IPv6.

Chains

Chains are used to group together rules. As with the tables, nftables does not have any predefined chains. Chains are grouped in base and non-base types. Base chains are registered in one of the netfilter hooks. A base chain has a hook its registered with, a type and a priority. Non-base chains are not attached to a hook and they don't see any traffic by default. They can be used to arrange a rule-set in a tree of chains. There are currently three types of chains:

  • filter: for filtering packets
  • route: for rerouting packets
  • nat: for performing Network Address Translation. Only the first packet of a flow hits this chain, making it impossible to use it for filtering.

The hooks that can be used are:

  • prerouting: This is before the routing decision, all packets entering the machine hits this chain
  • input: All packets for the local system hits this hook
  • forward: Packets not for the local system, those that need to be forwarded hits this hook
  • output: Packets that originate from the local system pass this hook
  • postrouting: This hook is after the routing decision, all packets leaving the machine hits this chain
   Note

The ARP address family only supports the input and output hook

   Note

The bridge address family only seems to supports the input, forward and output hook

Priorities

   Note

Priorities do not currently appear to have any effect on which chain sees packets first.

   Note

Since the priority seems to be an unsigned integer, negative priorities will be converted into very high priorities.

Rules

Rules specify which action has to be taken for which packets. Rules are attached to chains. Each rule can has an expression to match packets with and one or multiple actions when matching. Main differences with iptables is that it is possible to specify multiple actions and that by default counters are off. It must be specified explicitly in rules if you want packet- and byte-counters for a rule. Each rule has a unique handle number by which it can be distinguished. The following matches are available:

  • ip: IP protocol
  • ip6: IPv6 protocol
  • tcp: TCP protocol
  • udp: UDP protocol
  • udplite: UDP-lite protocol
  • sctp: SCTP protocol
  • dccp: DCCP protocol
  • ah: Authentication headers
  • esp: Encrypted security payload headers
  • ipcomp: IPcomp headers
  • icmp: icmp protocol
  • icmpv6: icmpv6 protocol
  • ct: Connection tracking
  • meta: meta properties such as interfaces

Matches

Match Arguments Description/Example
ip version Ip Header version
hdrlength IP header length
tos Type of Service
length Total packet length
id IP ID
frag-off Fragmentation offset
ttl Time to live
protocol Upper layer protocol
checksum IP header checksum
saddr Source address
daddr Destination address
ip6 version IP header version
priority
flowlabel Flow label
length Payload length
nexthdr Next header type (Upper layer protocol number)
hoplimit Hop limit
saddr Source Address
daddr Destination Address
tcp sport Source port
dport Destination port
sequence Sequence number
ackseq Acknowledgement number
doff Data offset
flags TCP flags
window Window
checksum Checksum
urgptr Urgent pointer
udp sport Source port
dport destination port
length Total packet length
checksum Checksum
udplite sport Source port
dport destination port
cscov Checksum coverage
checksum Checksum
sctp sport Source port
dport destination port
vtag Verification tag
checksum Checksum
dccp sport Source port
dport destination port
ah nexthdr Next header protocol (Upper layer protocol)
hdrlength AH header length
spi Security Parameter Index
sequence Sequence Number
esp spi Security Parameter Index
sequence Sequence Number
ipcomp nexthdr Next header protocol (Upper layer protocol)
flags Flags
cfi Compression Parameter Index
icmp type icmp packet type
icmpv6 type icmpv6 packet type
ct state State of the connection
direction Direction of the packet relative to the connection
status Status of the connection
mark Connection mark
expiration Connection expiration time
helper Helper associated with the connection
l3proto Layer 3 protocol of the connection
saddr Source address of the connection for the given direction
daddr Destination address of the connection for the given direction
protocol Layer 4 protocol of the connection for the given direction
proto-src Layer 4 protocol source for the given direction
proto-dst Layer 4 protocol destination for the given direction
meta length Length of the packet in bytes: meta length > 1000
protocol ethertype protocol: meta protocol vlan
priority TC packet priority
mark Packet mark
iif Input interface index
iifname Input interface name
iiftype Input interface type
oif Output interface index
oifname Output interface name
oiftype Output interface hardware type
skuid UID associated with originating socket
skgid GID associated with originating socket
rtclassid Routing realm

Statements

Statements represent the action to be performed when the rule matches. They exist in two kinds: Terminal statements, unconditionally terminate the evaluation of the current rules and non-terminal statements that either conditionally or never terminate the current rules. There can be an arbitrary amount of non-terminal statements, but there must be only a single terminal statement. The terminal statements can be:

  • accept: Accept the packet and stop the ruleset evaluation.
  • drop: Drop the packet and stop the ruleset evaluation.
  • reject: Reject the packet with an icmp message
  • queue: Queue the packet to userspace and stop the ruleset evaluation.
  • continue:
  • return: Return from the current chain and continue at the next rule of the last chain. In a base chain it is equivalent to accept
  • jump <chain>: Continue at the first rule of <chain>. It will continue at the next rule after a return statement is issued
  • goto <chain>: Similar to jump, but after the new chain the evaluation will continue at the last chain instead of the one containing the goto statement

Installing nftables

Kernel

These kernel options must be set Under Network support:

Networking options
        [*] Network packet filtering framework (Netfilter)  --->
            Core Netfilter Configuration  --->
                <M> Netfilter nf_tables support
                <M>   Netfilter nf_tables IPv6 exthdr module
                <M>   Netfilter nf_tables meta module
                <M>   Netfilter nf_tables conntrack module
                <M>   Netfilter nf_tables rbtree set module
                <M>   Netfilter nf_tables hash set module
                <M>   Netfilter nf_tables counter module
                <M>   Netfilter nf_tables log module
                <M>   Netfilter nf_tables limit module
                <M>   Netfilter nf_tables nat module
                <M>   Netfilter x_tables over nf_tables module
            IP: Netfilter Configuration  --->
                <M> IPv4 nf_tables support
                <M>   nf_tables IPv4 reject support
                <M>   IPv4 nf_tables route chain support
                <M>   IPv4 nf_tables nat chain support
            IPv6: Netfilter Configuration  --->
                <M> IPv6 nf_tables support
                <M>   IPv6 nf_tables route chain support
                <M>   IPv6 nf_tables nat chain support
            <M>   Ethernet Bridge nf_tables support

Emerging

To install nftables, run the following command:

root # emerge net-firewall/nftables


OpenRC configuration

Don't forget to add nftables service to startup:

root # rc-update add nftables default

You cannot use iptables and nft to perform NAT at the same time. So make sure that the iptable_nat module is unloaded. Remove iptables_nat module:

root # rmmod iptable_nat

Start nftables:

root # /etc/init.d/nftables start


Using nftables

All nftable commands are done with the nft ultility from net-firewall/nftables.

Tables

Creating tables

The following command adds a table called filter for the ip(v4) layer

root # nft add table ip filter

Likewise a table for arp can be created with

root # nft add table arp filter
   Note

The name "filter" used here is completly arbitrary. It could have any name

Listing tables

The following command lists all tables for the ip(v4) layer

root # nft list tables ip
table filter

The contents of the table filter can be listed with:

root # nft list table ip filter
table ip filter {
        chain input {
                 type filter hook input priority 0;
                 ct state established,related accept
                 iifname "lo" accept
                 ip protocol icmp accept
                 drop
        }
}

using -a with the nft command, it shows the handle of each rule. Handles are used for various operations on specific rules:

root # nft -a list table ip filter
table ip filter {
        chain input {
                 type filter hook input priority 0;
                 ct state established,related accept # handle 2
                 iifname "lo" accept # handle 3
                 ip protocol icmp accept # handle 4
                 drop # handle 5
        }
}

Deleting tables

The following command deletes the table called filter for the ip(v4) layer:

root # nft delete table ip filter

chains

Adding chains

The following command adds a chain called input to the ip filter table and registered to the input hook with priority 0. It is of the type filter.

root # nft add chain ip filter input { type filter hook input priority 0 \; }
   Note

If You're running this command from Bash you need to escape the semicolon

A non-base chain can be added by not specifying the chain configurations between the curly braces.

Removing chains

The following command deletes the chain called input

root # nft delete chain ip filter input
   Note

Chains can only be deleted if there are no rules in them.

rules

Adding rules

The following command adds a rule to the chain called input, on the ip filter table, dropping all traffic to port 80:

root # nft add rule ip filter input tcp dport 80 drop

Deleting Rules

To delete a rule, you first need to get the handle number of the rule. This can be done by using the -a flag on nft:

root # nft  rule ip filter input tcp dport 80 drop
table ip filter {
        chain input {
                 type filter hook input priority 0;
                 tcp dport http drop # handle 2
        }
}

It is then possible to delete the rule with:

root # nft delete rule ip filter input handle 2

Management

Backup

You can also backup your rules:

root # echo "nft flush ruleset" > backup.nft
root # nft list ruleset >> backup.nft

Restoration

And load it atomically:

root # nft -f backup.nft

OpenRC configuration

Don't forget to add nftables service to startup:

root # rc-update add nftables default

Init script (firewall nftables like a iptables)

#!/sbin/runscript
#      Raphael Bastos aka coffnix        #
#      Init Script for Funtoo Linux      #
##########################################

depend() {
        need net
        need nftables
        }

start(){
##################### PARTE 1 #####################
ebegin "Starting Firewall NFTables"

#######################################################################
### Incompatibilities ###
# You cannot use iptables and nft to perform NAT at the same time.
# So make sure that the iptable_nat module is unloaded
rmmod iptable_nat

#######################################################################

echo 1 > /proc/sys/net/ipv4/ip_forward
echo 1 > /proc/sys/net/ipv4/ip_dynaddr
echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
for f in /proc/sys/net/ipv4/conf/*/rp_filter ; do echo 1 > $f ; done

#######################################################################

iptables -t nat -F

#######################################################################

# ipv4
nft -f /etc/nftables/ipv4-filter

# ipv4 nat
nft -f /etc/nftables/ipv4-nat

# ipv6
nft -f /etc/nftables/ipv6-filter

# Rules firewall NTFtables
nft -f /etc/nftables/firewall.rules

#######################################################################

}

stop(){
ebegin "Stoping Firewall NFTables"

#######################################################################

#iptables -t nat -F
NFT=nft
FAMILIES="ip ip6 arp bridge"

for FAMILY in $FAMILIES; do
  TABLES=$($NFT list tables $FAMILY | grep "^table\s" | cut -d' ' -f2)

  for TABLE in $TABLES; do
    CHAINS=$($NFT list table $FAMILY $TABLE | grep "^\schain\s" | cut -d' ' -f2)

    for CHAIN in $CHAINS; do
      echo "Flushing chain: $FAMILY->$TABLE->$CHAIN"
      $NFT flush chain $FAMILY $TABLE $CHAIN
      $NFT delete chain $FAMILY $TABLE $CHAIN
    done

    echo "Flushing table: $FAMILY->$TABLE"
    $NFT flush table $FAMILY $TABLE
    $NFT delete table $FAMILY $TABLE
  done
done
}

status(){
nft list ruleset
}

# End

Personal Rules

And configure your personal rules:

# A simple firewall
#

table ip filter {
        chain input {
                type filter hook input priority 0;
                ct state established,related accept

                # invalid connections
                ct state invalid drop

                # loopback interface
                iifname "lo" accept

                # icmp
                ip protocol icmp accept

                # open ports
                #tcp dport {ssh, http} accept
                #udp dport {5060} accept
                #udp dport {4000-20000} accept

                # Bind DNS Server
                udp sport domain accept
                tcp sport domain accept


                # LAN
                #ip saddr 192.168.100.0/24 ct state new counter accept

                # everything else
                drop
        }
        chain forward {
                #ip daddr 192.168.100.0/24 accept
        }
}


table ip6 filter {
        chain input {
                type filter hook input priority 0;

                # established/related connections
                ct state established,related accept

                # invalid connections
                ct state invalid drop

                # loopback interface
                iifname lo accept

                # icmp
                ip6 nexthdr icmpv6 accept

                # open tcp ports: sshd (22), httpd (80)
                #tcp dport {ssh, http} accept
                #udp dport {5060} accept
                #udp dport {4000-20000} accept

                # everything else
                drop
        }
}


table ip nat {
        chain prerouting {
                #tcp dport 8081 ip protocol tcp counter dnat 192.168.100.24
        }
        chain postrouting {
                #masquerade random,persistent
                #ip saddr 192.168.100.0/24 oif eth0 snat 192.168.25.3
        }

}