How to log rejected packets

LEDE is a versatile platform base on GNU/Linux, offering state-of-the art solutions relying on GNU/Linux iptables to filter and inspect packets. By default, as logging can degrade performance, LEDE does not log rejected packets. This HOWTO explain how to enable logging of REJECTED packets in LEDE.

This article still needs review. Please discuss this article for review here: https://forum.lede-project.org/t/call-for-review-how-to-log-rejected-packets .

In LEDE, only REJECTED packets can be logged.

Before choosing to enable logging of REJECTED packets, please consider pros and cons:

  • DROPPED packets are discarded by LEDE, i.e. “trashed” without further notice. DROPPING packets does not require too much computing power, nor network bandwidth. This is also more resistent to DoS attacks, as no answer is sent.
  • On the converse, REJECTED packets require more computing power, as an answer is sent to client. Logging REJECTED packets also consume computing power. Logging may also display continuous messages on the serial port if you connect via serial console (not via SSH). You also need another device to log packets, as logging packets on the same device is not recommended.

Here is an example of the WAN zone :

  config zone
  option name 'wan'
  option input 'REJECT'
  option output 'ACCEPT'
  option forward 'REJECT'
  option masq '1'
  option mtu_fix '1'
  option network 'wan wan6'
  option log '1'
  option log_limit '5/second'   

In these settings, INPUT and FORWARDED packets are logged when REJECTED and written to system log with a limit of 5 messages per second.

The log_limit is inherited from GNU/Linux iptables:

 limit is followed by a number; specifies the maximum average number of matches to allow per second. The number can specify units explicitly, using /second’,/minute’, /hour’ or/day’, or parts of them (so 5/second’ is the same as5/s’).

In Firewall → General settings:

  • Make sure that packets are not dropped, only rejected.
  • Case by case, select “reject” and not “drop”

In Firewall Zones:

  • → Advanced settings
  • Check [x] Enable logging on this zone
  • Fill in the Limit log messages value.

Using console, run the following command to display all filtering rules:

iptables -L

The logging rules of our previous example have become:

Chain zone_wan_dest_REJECT (1 references)
target     prot opt source               destination         
LOG        all  --  anywhere             anywhere             limit: avg 5/sec burst 5 /* !fw3 */ LOG level warning prefix "REJECT(dest wan)"
reject     all  --  anywhere             anywhere             /* !fw3 */
reject     all  --  anywhere             anywhere             /* !fw3 */

[…]

Chain zone_wan_src_REJECT (1 references)

target     prot opt source               destination         
LOG        all  --  anywhere             anywhere             limit: avg 5/sec burst 5 /* !fw3 */ LOG level warning prefix "REJECT(src wan)"
reject     all  --  anywhere             anywhere             /* !fw3 */
reject     all  --  anywhere             anywhere             /* !fw3 */

Here, we discover that LEDE limit covers both iptables limit and burst limit. Burst limit is the limit during the first microseconds of an event. In order to avoid DoS attack, LEDE covers both average and burst syntax. However, you should know that an attacker sending hundreds of rejected “probes” within the first microseconds, would probably generate only 5 logging messages. Therefore, to detect DoS attacks, you might need to raise limit to a higher lever. But again, this could degrade performance or worse, your device might not be able to cope with such hardware stress.

LEDE firewalling relies on zones. For each zone, there are INPUT and OUTPUT chains (among others). Each zone can have a single LOG chain.

In more complex firewalling implementations, like fwBuilder for iptables, also a Free Software, there is an INPUT and OUTPUT chain per rule, which makes it possible to label each rule with a prefix, including rule number. Below is an example of logging rule generated by fwBuilder to monitor iPerf3 traffic:

$IPTABLES -N In_RULE_6
$IPTABLES -A INPUT -i enp0s29u1u1  -p tcp -m tcp  --dport 5201:5203  -m state --state NEW  -j In_RULE_6
$IPTABLES -A INPUT -i eth0  -p tcp -m tcp  --dport 5201:5203  -m state --state NEW  -j In_RULE_6
$IPTABLES -A In_RULE_6  -j LOG  --log-level info --log-prefix "VAIO 6 -- ACCEPT "
$IPTABLES -A In_RULE_6  -j ACCEPT
$IPTABLES -N Cid26872X7681.0
$IPTABLES -A OUTPUT -o enp0s29u1u1  -p tcp -m tcp  --dport 5201:5203  -m state --state NEW  -j Cid26872X7681.0
$IPTABLES -N Out_RULE_6
for i_enp0s29u1u1 in $i_enp0s29u1u1_list
do
test -n "$i_enp0s29u1u1" && $IPTABLES -A Cid26872X7681.0  -d $i_enp0s29u1u1   -j Out_RULE_6 
done
for i_eth0 in $i_eth0_list
do
test -n "$i_eth0" && $IPTABLES -A Cid26872X7681.0  -d $i_eth0   -j Out_RULE_6 
done
$IPTABLES -N Cid26872X7681.1
$IPTABLES -A OUTPUT -o eth0  -p tcp -m tcp  --dport 5201:5203  -m state --state NEW  -j Cid26872X7681.1
for i_enp0s29u1u1 in $i_enp0s29u1u1_list
do
test -n "$i_enp0s29u1u1" && $IPTABLES -A Cid26872X7681.1  -d $i_enp0s29u1u1   -j Out_RULE_6 
done
for i_eth0 in $i_eth0_list
do
test -n "$i_eth0" && $IPTABLES -A Cid26872X7681.1  -d $i_eth0   -j Out_RULE_6 
done
$IPTABLES -A Out_RULE_6  -j LOG  --log-level info --log-prefix "VAIO 6 -- ACCEPT "
$IPTABLES -A Out_RULE_6  -j ACCEPT

$IP6TABLES -N In_RULE_6
$IP6TABLES -A INPUT -i enp0s29u1u1  -p tcp -m tcp  --dport 5201:5203  -m state --state NEW  -j In_RULE_6
$IP6TABLES -A INPUT -i eth0  -p tcp -m tcp  --dport 5201:5203  -m state --state NEW  -j In_RULE_6
$IP6TABLES -A In_RULE_6  -j LOG  --log-level info --log-prefix "VAIO 6 -- ACCEPT "
$IP6TABLES -A In_RULE_6  -j ACCEPT
$IP6TABLES -N Cid26872X7681.0
$IP6TABLES -A OUTPUT -o enp0s29u1u1  -p tcp -m tcp  --dport 5201:5203  -m state --state NEW  -j Cid26872X7681.0
$IP6TABLES -N Out_RULE_6
for i_enp0s29u1u1_v6 in $i_enp0s29u1u1_v6_list
do
test -n "$i_enp0s29u1u1_v6" && $IP6TABLES -A Cid26872X7681.0  -d $i_enp0s29u1u1_v6   -j Out_RULE_6 
done
for i_eth0_v6 in $i_eth0_v6_list
do
test -n "$i_eth0_v6" && $IP6TABLES -A Cid26872X7681.0  -d $i_eth0_v6   -j Out_RULE_6 
done
$IP6TABLES -N Cid26872X7681.1
$IP6TABLES -A OUTPUT -o eth0  -p tcp -m tcp  --dport 5201:5203  -m state --state NEW  -j Cid26872X7681.1
for i_enp0s29u1u1_v6 in $i_enp0s29u1u1_v6_list
do
test -n "$i_enp0s29u1u1_v6" && $IP6TABLES -A Cid26872X7681.1  -d $i_enp0s29u1u1_v6   -j Out_RULE_6 
done
for i_eth0_v6 in $i_eth0_v6_list
do
test -n "$i_eth0_v6" && $IP6TABLES -A Cid26872X7681.1  -d $i_eth0_v6   -j Out_RULE_6 
done
$IP6TABLES -A Out_RULE_6  -j LOG  --log-level info --log-prefix "VAIO 6 -- ACCEPT "
$IP6TABLES -A Out_RULE_6  -j ACCEPT

For example, packets complying with iPerf3 are logged in custom chains (IPv4) In_RULE_6 and Out_Rule_6:

$IPTABLES -A In_RULE_6  -j LOG  --log-level info --log-prefix "VAIO 6 -- ACCEPT "
$IPTABLES -A Out_RULE_6  -j LOG  --log-level info --log-prefix "VAIO 6 -- ACCEPT "

The same is written for IPv6:

$IPTABLES6 -A In_RULE_6  -j LOG  --log-level info --log-prefix "VAIO 6 -- ACCEPT "
$IPTABLES6 -A Out_RULE_6  -j LOG  --log-level info --log-prefix "VAIO 6 -- ACCEPT "

The prefix “VAIO 6” indicates the name of the server and the rule number in fwBuilder GUI.

It makes it possible to send all loggin to a central Syslog server and quickly analyse situations.

This clearly show that only REJECTED packets can be logged. Logging traffic in full details like in a traditional firewall would require vast modification of LEDE/OpenWRT firewall implementation, adding a INPUT and OUTPUT for each rule. Before and if this is done, you may use fwBuilder to generate custom firewalling rules. Which is our next article.