{{tag>linux nft nftables nmap}} =====NFTables IP Control===== I primarily set this feature up to act as a form of parental control on my home internet access. ====Disable Range of IP addresses, with count-down timer==== The DHCP assigned addresses in the range 100 - 254 were to be disabled (dropped) in the evening. The addresses below 100 were assigned a specific IP address in the DHCP based upon MAC. I added a [[https://wiki.nftables.org/wiki-nftables/index.php/Sets#Named_sets|NFtables named set]] with ipV4 address and timeout function: set controllist { type ipv4_addr flags interval flags timeout } In the forward chain the controllist IP set was dropped for all the source and destination packets. ip daddr @controllist counter drop ip saddr @controllist counter drop ++++Router NFtable Setup - with named set IP filtering| #!/usr/sbin/nft -f define wan = ppp1 define modem = eno1 define lan = br0 define router_ip4 = 192.168.1.1 define http_server = 192.168.1.12 define mail_server = 192.168.1.18 define wan_ip4 = 112.213.222.38 # Clean out the current ruleset flush ruleset table inet firewall { set controllist { type ipv4_addr flags interval flags timeout } # Remember that the input and output chains only refer to this machine. # The forward and nat chains refer to routing. # open ports refers to ports to open for input to this machine. # ssh is port 22 for SSH on both TCP and UDP, but we only use TCP! # bootps, port 67 and bootpc, port 68 are for DHCP on both TCP and UDP, # but we only use UDP! # domain is port 53 for DNS requests on TCP & UDP. # openvnp is port 1194 on both TCP and UDP, but we are not using yet. # set tcp_open_ports { # type inet_service; flags interval; # elements = { ; } # ssh # domain # openvpn # http # https # } # set udp_open_ports { # type inet_service; flags interval; # elements = { ; } # domain # bootps # bootpc # openvpn # } chain base_checks { # allow established/related connections ct state {established, related} counter accept # early drop of invalid connections ct state invalid counter drop } chain tcp_cek { # bad tcp -> avoid network scanning: tcp flags & (fin|syn) == (fin|syn) counter drop tcp flags & (syn|rst) == (syn|rst) counter drop tcp flags & (fin|syn|rst|psh|ack|urg) < (fin) counter drop tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|psh|urg) counter drop } chain input { type filter hook input priority 0; policy drop; # drop invalid state packets ct state invalid counter drop # Cek valid tcp packet ip protocol tcp jump tcp_cek tcp dport ssh counter # accept established connections ct state established, related counter accept # no ping floods: ip protocol icmp limit rate over 5/second counter drop # drop connections from blacklisted addresses # ip saddr @blacklist counter drop # avoid brute force on ssh: (if using external ssh) tcp dport ssh limit rate over 8/minute counter drop # allow icmp ip protocol icmp icmp type { echo-request, echo-reply, time-exceeded, parameter-problem, destination-unreachable } counter accept # accept input from loopback interface iif lo counter accept # accept input from LAN iifname $lan counter accept # By port is a pain in the arse! # iifname $lan tcp dport { ssh, domain, 667, 953 } counter accept # iifname $lan udp dport { domain, bootps, bootpc, 667, 953} counter accept # allow tcp/udp open ports # tcp dport @tcp_open_ports counter accept # udp dport @udp_open_ports counter accept # everything else reject port unreachable # reject with icmpx type port-unreachable } chain forward { type filter hook forward priority 0; policy accept; #drop all IP addresses in the control list both source and destination ip daddr @controllist counter drop ip saddr @controllist counter drop #oifname $wan tcp flags syn tcp option maxseg size set rt mtu oifname $wan tcp flags syn tcp option maxseg size set 1452 counter iifname $wan oifname $lan jump base_checks iifname $lan oifname $wan counter accept #Allow traffic between private LANs (to/from modem) iifname $lan oifname $modem accept #iifname $modem oifname $lan accept iifname $modem oifname $lan jump base_checks #ip saddr 192.168.5.1 oifname $lan accept # Allow coming out of the vpn # ip saddr 192.168.2.0/24 iifname tun0 accept # Allow new connections to internal servers, # but only those that have had dnat performed. # The server names can be used where host DNS # resolves to IP address #tcp dport { http, https } ct state new counter accept ip daddr $http_server ct status dnat counter accept ip daddr $mail_server ct status dnat counter accept # iifname "he-ipv6" counter packets 0 bytes 0 jump base_checks # iifname "br0" oifname "he-ipv6" counter packets 0 bytes 0 accept } chain output { # We allow everything out type filter hook output priority 0; policy accept; } } table ip nat { #map tcp_nat_map { # type inet_service : ipv4_addr # elements = { http : 192.168.1.16, https : 192.168.1.16} #} #map udp_nat_map { # type inet_service : ipv4_addr #} chain wan_in { tcp dport { http, https} counter dnat $http_server tcp dport { pop3s, imaps, smtp} counter dnat $mail_server # dnat tcp dport map @tcp_nat_map # dnat udp dport map @udp_nat_map } chain prerouting { type nat hook prerouting priority 0; policy accept; iifname $wan jump wan_in # Allow internal clients to correctly see external address "hairpin dnat" ip daddr $wan_ip4 tcp dport {http, https} counter dnat $http_server ip daddr $wan_ip4 tcp dport {pop3s, imaps, smtp} counter dnat $mail_server } chain postrouting { type nat hook postrouting priority 0; policy accept; # Allow internal clients to correctly see external address "hairpin dnat" ip saddr 192.168.1.0/24 ip daddr $http_server tcp dport {http, https} counter snat $router_ip4 ip saddr 192.168.1.0/24 ip daddr $mail_server tcp dport {http, https, pop3s, imaps, smtp} counter snat $router_ip4 oifname $wan counter masquerade oifname $modem counter masquerade #oifname {$wan, tun0} masquerade # For Static IP address use SNAT instead of masquerade # ip saddr 192.168.1.0/24 oif $wan snat $wan_ip4 # oifname $modem snat 192.168.2.2 # oifname $modem masquerade # where the snat address is the external router fix IP address. } } ++++ Some important NFtables Commands with named sets: *''sudo nft list table inet firewall'' : will list all the active firewall table *''sudo nft add element inet firewall controllist { 192.168.1.130 timeout 5m}'' : will add the IPv4 address 192.168.1.130 to the named set controllist for 5 minutes *where timeout values are: ''h m s'' and can be used in tandem as such: ''5h30m'' for 5 hours 30 minutes. *''sudo nft list set inet firewall controllist'' : will list the current elements in named set controllist *''sudo nft flush set inet firewall controllist'' : will flush the current named set controllist *''sudo vim /etc/nftables.conf'' : to edit the current NFTables configuration *''sudo systemctl restart nftables'' to restart with the current nftables configuration *''status'' to list current running status of nftables *''start'' to start nftables with the current configuration *''stop'' to stop nftables *''journalctl -b0 -xe -u nftables'' to list the end of all the nftables journal entries since the last boot I made a couple of bash scripts to assist with the use of these controllist name sets. *''sudo vim controllist.sh'' : This script automates the entry of a a range of IP address with timeout limits in the the named set. (The timeout option does not seem to function with the interval option.) ++++controllist.sh| #!/bin/bash if [ -z "$1" ] then timeout1=' timeout 5h' else timeout1=" timeout $1" fi cmd1='/usr/sbin/nft add element inet firewall controllist { ' ipbase='192.168.1.' for i in {100..254} do cmd1="${cmd1}${ipbase}${i} ${timeout1}, " done cmd1="${cmd1} }" eval "$cmd1"; ++++ * A key change to this script to improve functionality would be to allow an input of the timer duration. *''sudo vim deletecontrol.sh'' : This is a simple script to flush the control list. ++++deletecontrol.sh| #!/bin/bash nft flush set inet firewall controllist ++++ *Do not forget to run ''sudo chmod 774 controllist.sh'' on the script files to make them executable I then created a cron job to run the script as required every evening *''sudo crontab -l'' : to list current cron jobs (use sudo for root) *''sudo crontab -e'' : to edit the cornjobs *''journalctl -b0 -u cron | grep control'' : to list all the related cron jobs since last boot ''crontab'' is finicky! crontab does not necessary use BASH and the full path to the command must be given for reliable performance. Further to this cron error messages are sent to the system mail server, so if this is not setup or otherwise not working the error message go nowhere. Systemd has a service to redirect output of cron jobs to systemd's journal: ''/usr/bin/systemd-cat -t controllist'', again the full path is given. The command path can be found using ''which'', e.g. ''which nft''. In any case the final crontab command entry would look like: ''/usr/bin/systemd-cat -t controllist /home/baumkp/controllist.sh'', remembering everything after the 5th space is passed to the system shell command interpreter. ++++ example: ''sudo crontab -e'' | # Edit this file to introduce tasks to be run by cron. # # Each task to run has to be defined through a single line # indicating with different fields when the task will be run # and what command to run for the task # # To define the time you can provide concrete values for # minute (m), hour (h), day of month (dom), month (mon), # and day of week (dow) or use '*' in these fields (for 'any'). # # Notice that tasks will be started based on the cron's system # daemon's notion of time and timezones. # # Output of the crontab jobs (including errors) is sent through # email to the user the crontab file belongs to (unless redirected). # # For example, you can run a backup of all your user accounts # at 5 a.m every week with: # 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/ # # For more information see the manual pages of crontab(5) and cron(8) # # m h dom mon dow command # Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat,sun # | | | | | # * * * * * user-name command to be executed # 45 23 * * * /usr/bin/systemd-cat -t controllist /home/baumkp/controllist.sh 5h15m # 30 23 * * 5-6 /usr/bin/systemd-cat -t controllist /home/baumkp/controllist.sh 5h30m # 30 22 * * 0-4 /usr/bin/systemd-cat -t controllist /home/baumkp/controllist.sh 6h30m ++++ The crontab files are stored at ''/var/spool/cron/crontabs/$USER''. You should not edit these files directly, use ''crontab -e'' for current user or ''sudo crontab -e'' for root. ====Limit Rate on IP Address Range==== The rate limit command needs to be placed before the other commands that could accept packets before reaching the rate limit command, e.g. ''ct state established, related counter accept''. The following command will add the command at handle 29: *''sudo nft add rule inet firewall forward handle 29 iifname ppp1 ip daddr { 192.168.1.100-192.168.1.253 } limit rate 1200kbytes/second burst 4000kbytes counter accept'' The existing rules with handles displayed can be displayed with: *''sudo nft list table inet firewall -a'' The above command will accept packets according to filter that do not exceed 1200kbytes/second with a burst of 9000kbytes. Another form of syntax would be to drop packets that exceed the limit, this allows the amount of drop packets to be seen with the counter enabled: *''sudo nft add rule inet firewall forward handle 29 iifname ppp1 ip daddr { 192.168.1.100-192.168.1.253 } limit rate over 1200kbytes/second burst 4000kbytes counter drop'' My internet bandwidth is currently limited to about 25Mbit/s, dividing by 8 give approximate MByte/s, i.e. about 3MB/s or 3000mbytes/s or 3000kbytes/s, hence I limit the kids bandwidth to 1200kbytes/s with an allowed burst of 4000kbytes. ====Some other tools==== *''sudo nmap -sn 192.168.1.0/24'' *''-sP'' lists all IP addresses with any open port (with sudo will also list mac addresses) *''-sL'' lists all IP addresses even not active *''-sT'' lists all IP addresses with all open ports (with sudo will also list mac addresses) Note this can take a long time so better to limit IP address range. *''-sn'' Ping scan, does not scan for port and is hence much faster (with sudo will also list mac addresses) ---- <- linux_router:nftables|Prev page ^ linux_router:start|Start page ^ linux_router:iptables|Next page ->