diff --git a/config/cfgroot/udp-ddos-settings b/config/cfgroot/udp-ddos-settings new file mode 100644 index 000000000..e601658ef --- /dev/null +++ b/config/cfgroot/udp-ddos-settings @@ -0,0 +1,5 @@ +53=off +ENABLE_UDP_DDOS=off +5060=off +5061=off +10408=off diff --git a/config/cfgroot/udp_ports b/config/cfgroot/udp_ports new file mode 100644 index 000000000..a4735fd02 --- /dev/null +++ b/config/cfgroot/udp_ports @@ -0,0 +1,5 @@ +domain 53/udp # Domain Name Server +game1 10408/udp # Domain Name Server +sip 5060/udp # Voice over Internet +siptls 5061/udp # Voice over Internet TLS + diff --git a/html/cgi-bin/ddos.cgi b/html/cgi-bin/ddos.cgi index 9ee356d9e..4cd5a6dd7 100755 --- a/html/cgi-bin/ddos.cgi +++ b/html/cgi-bin/ddos.cgi @@ -3,7 +3,7 @@ # # # IPFire.org - A linux based firewall # # Copyright (C) 2007-2020 IPFire Team # -# Copyright (C) 2024 FireBeeOS # +# Copyright (C) 2024 BPFire # # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # @@ -36,14 +36,19 @@ require "${General::swroot}/header.pl"; my %color = (); my %mainsettings = (); my %ddossettings=(); +my %udpddossettings=(); my %checked=(); my $errormessage=''; my $counter = 0; my %tcp_ports=(); -my $portfile = "${General::swroot}/ddos/tcp_ports"; +my %udp_ports=(); +my $tcp_portfile = "${General::swroot}/ddos/tcp_ports"; +my $udp_portfile = "${General::swroot}/ddos/udp_ports"; my $ddossettingfile = "${General::swroot}/ddos/settings"; +my $udpddossettingfile = "${General::swroot}/ddos/udp-ddos-settings"; &get_tcp_ports(); +&get_udp_ports(); # Read configuration file. @@ -53,7 +58,10 @@ my $ddossettingfile = "${General::swroot}/ddos/settings"; &Header::showhttpheaders(); $ddossettings{'ENABLE_DDOS'} = 'off'; +$udpddossettings{'ENABLE_UDP_DDOS'} = 'off'; $ddossettings{'ACTION'} = ''; +$udpddossettings{'UDP_ACTION'} = ''; + &Header::getcgihash(\%ddossettings); if ($ddossettings{'ACTION'} eq $Lang::tr{'save'}) @@ -84,17 +92,38 @@ if ($ddossettings{'ACTION'} eq $Lang::tr{'save'}) } -# Read configuration file. -&General::readhash("$ddossettingfile", \%ddossettings); +&Header::getcgihash(\%udpddossettings); + +if ($udpddossettings{'UDP_ACTION'} eq $Lang::tr{'save'}) +{ + + # Loop through our locations array to prevent from + # non existing countries or code. + foreach my $p (values %udp_ports) { + # Check if blocking for this country should be enabled/disabled. + if (exists $udpddossettings{$p}) { + $udpddossettings{$p} = "on"; + } else { + $udpddossettings{$p} = "off"; + } + } + + &General::writehash("$udpddossettingfile", \%udpddossettings); + + if ($udpddossettings{'ENABLE_UDP_DDOS'} eq 'on') { + &General::log($Lang::tr{'ddos is enabled'}); + &General::system('/usr/bin/touch', "${General::swroot}/ddos/enableddos"); + &General::system('/usr/local/bin/ddosctrl', 'start'); + } else { + &General::log($Lang::tr{'ddos is disabled'}); + &General::system('/usr/local/bin/ddosctrl', 'stop'); + unlink "${General::swroot}/ddos/enableddos"; + } + +} &Header::openpage($Lang::tr{'ebpf xdp ddos'}, 1, ''); -# Checkbox pre-selection. -my $checked; -if ($ddossettings{'ENABLE_DDOS'} eq "on") { - $checked = "checked='checked'"; -} - &Header::openbigbox('100%', 'left', '', $errormessage); if ($errormessage) { @@ -103,10 +132,19 @@ if ($errormessage) { &Header::closebox(); } +# Read configuration file. +&General::readhash("$ddossettingfile", \%ddossettings); + +# Checkbox pre-selection. +my $checked; +if ($ddossettings{'ENABLE_DDOS'} eq "on") { + $checked = "checked='checked'"; +} + # Print box to enable/disable locationblock. print"
\n"; -&Header::openbox('100%', 'center', $Lang::tr{'xdp'}); +&Header::openbox('100%', 'center', $Lang::tr{'xdp tcp'}); print < @@ -120,7 +158,7 @@ END &Header::closebox(); -&Header::openbox('100%', 'center', $Lang::tr{'xdp port'}); +&Header::openbox('100%', 'center', $Lang::tr{'xdp tcp port'}); print < @@ -206,6 +244,116 @@ END print "\n"; +# Read configuration file. +&General::readhash("$udpddossettingfile", \%udpddossettings); + +# Checkbox pre-selection. +my $udp_checked; +if ($udpddossettings{'ENABLE_UDP_DDOS'} eq "on") { + $udp_checked = "checked='checked'"; +} + +# Print box to enable/disable locationblock. +print"
\n"; + +&Header::openbox('100%', 'center', $Lang::tr{'xdp udp'}); +print < + + $Lang::tr{'xdp enable'} + + + + + +END + +&Header::closebox(); + +&Header::openbox('100%', 'center', $Lang::tr{'xdp udp port'}); +print < + + + + $Lang::tr{'port'} + + + $Lang::tr{'service'} + + +   + + + + $Lang::tr{'port'} + + + $Lang::tr{'service'} + + + +END + +my $udp_lines; +my $udp_lines2; +my $udp_col; + +# Sort output based on hash value port number +for my $service ( sort { $udp_ports{$a} cmp $udp_ports{$b} } + keys %udp_ports ) +{ + my $port = $udp_ports{$service}; + + # Checkbox pre-selection. + my $checked; + if ($udpddossettings{$port} eq "on") { + $checked = "checked='checked'"; + } + + # Colour lines. + if ($udp_lines % 2) { + $col="bgcolor='$color{'color20'}'"; + } else { + $col="bgcolor='$color{'color22'}'"; + } + + # Grouping elements. + my $line_start; + my $line_end; + if ($udp_lines2 % 2) { + # Increase lines (background color by once. + $lines++; + + # Add empty column in front. + $line_start=" "; + + # When the line number can be diveded by "2", + # we are going to close the line. + $line_end=""; + } else { + # When the line number is not divideable by "2", + # we are starting a new line. + $line_start=""; + $line_end; + } + + print "$line_start\n"; + print "$port\n"; + print "$service$line_end\n"; + +$udp_lines2++; +} +print < + +END + +&Header::closebox(); + +print "\n"; + &Header::openbox('100%', 'center', $Lang::tr{'xdp status'}); print <\n\n"; sub get_tcp_ports() { - open(my $fh, '<', $portfile) or die "Unable to open file: $!"; + my $fh; + open($fh, '<', $tcp_portfile) or die "Unable to open file: $!"; while (my $line = <$fh>) { chomp $line; next if $line =~ /^\s*#/; # Skip comments @@ -262,6 +411,21 @@ sub get_tcp_ports() close($fh); } +sub get_udp_ports() +{ + my $fh; + open($fh, '<', $udp_portfile) or die "Unable to open file: $!"; + while (my $line = <$fh>) { + chomp $line; + next if $line =~ /^\s*#/; # Skip comments + my ($service, $port) = $line =~ /^(\w+)\s+(\d+)\/udp/; + if ($service && $port) { + $udp_ports{$service} = $port; + } + } + close($fh); +} + sub printxdp() { # print active SSH logins (grep outpout of "who -s") diff --git a/langs/en/cgi-bin/en.pl b/langs/en/cgi-bin/en.pl index 30284762d..53f81c11c 100644 --- a/langs/en/cgi-bin/en.pl +++ b/langs/en/cgi-bin/en.pl @@ -1513,9 +1513,11 @@ 'intrusion prevention system' => 'Intrusion Prevention System', 'ebpf xdp ddos' => 'eBPF XDP DDoS Protection', 'ebpf xdp ddos system' => 'eBPF XDP DDoS Protection System', -'xdp' => 'XDP', -'xdp enable' => 'Enable XDP DDoS Feature', -'xdp port' => 'XDP DDoS Protected TCP Ports', +'xdp tcp' => 'XDP TCP', +'xdp udp' => 'XDP UDP', +'xdp enable' => 'Enable DDoS', +'xdp tcp port' => 'TCP Ports', +'xdp udp port' => 'UDP Ports', 'xdp status' => 'XDP Program Status', 'xdp interface' => 'Interface', 'xdp prio' => 'Prio', diff --git a/lfs/configroot b/lfs/configroot index d4989248e..06c02752a 100644 --- a/lfs/configroot +++ b/lfs/configroot @@ -68,7 +68,7 @@ $(TARGET) : fwhosts/customnetworks fwhosts/customhosts fwhosts/customgroups fwhosts/customservicegrp fwhosts/customlocationgrp fwlogs/ipsettings fwlogs/portsettings ipblocklist/modified \ ipblocklist/settings mac/settings main/hosts main/routing main/security main/settings optionsfw/settings \ ovpn/ccd.conf ovpn/ccdroute ovpn/ccdroute2 pakfire/settings portfw/config ppp/settings-1 ppp/settings-2 ppp/settings-3 ppp/settings-4 \ - ppp/settings-5 ppp/settings proxy/settings proxy/squid.conf proxy/advanced/settings proxy/advanced/cre/enable remote/settings ddos/settings ddos/tcp_ports qos/settings qos/classes qos/subclasses qos/level7config qos/portconfig \ + ppp/settings-5 ppp/settings proxy/settings proxy/squid.conf proxy/advanced/settings proxy/advanced/cre/enable remote/settings ddos/settings ddos/tcp_ports ddos/udp-ddos-settings ddos/udp_ports qos/settings qos/classes qos/subclasses qos/level7config qos/portconfig \ qos/tosconfig suricata/settings vpn/config vpn/settings vpn/ipsec.conf \ vpn/ipsec.secrets vpn/caconfig wakeonlan/clients.conf wireless/config wireless/settings; do \ touch $(CONFIG_ROOT)/$$i; \ @@ -100,6 +100,8 @@ $(TARGET) : cp $(DIR_SRC)/config/cfgroot/ssh-settings $(CONFIG_ROOT)/remote/settings cp $(DIR_SRC)/config/cfgroot/ddos-settings $(CONFIG_ROOT)/ddos/settings cp $(DIR_SRC)/config/cfgroot/tcp_ports $(CONFIG_ROOT)/ddos/tcp_ports + cp $(DIR_SRC)/config/cfgroot/udp-ddos-settings $(CONFIG_ROOT)/ddos/udp-ddos-settings + cp $(DIR_SRC)/config/cfgroot/udp_ports $(CONFIG_ROOT)/ddos/udp_ports cp $(DIR_SRC)/config/cfgroot/time-settings $(CONFIG_ROOT)/time/settings cp $(DIR_SRC)/config/cfgroot/logging-settings $(CONFIG_ROOT)/logging/settings cp $(DIR_SRC)/config/cfgroot/ethernet-vlans $(CONFIG_ROOT)/ethernet/vlans diff --git a/src/initscripts/system/ddos b/src/initscripts/system/ddos index bf5f9e6f5..fc7f58040 100755 --- a/src/initscripts/system/ddos +++ b/src/initscripts/system/ddos @@ -28,6 +28,7 @@ eval $(/usr/local/bin/readhash /var/ipfire/ddos/settings) get_ports () { # Define an empty variable to store the output local output="" + local ddos_port_file="$1" # Read the input file line by line while IFS= read -r line; do @@ -38,38 +39,38 @@ get_ports () { # Append the service/port number to the output string output="$output$service," fi - done < /var/ipfire/ddos/settings + done < $ddos_port_file # Remove the trailing comma from the output string output="${output%,}" echo $output } -ports="$(get_ports)" +tcp_ports="$(get_ports /var/ipfire/ddos/settings)" case "$1" in start) boot_mesg -n "Starting ddos..." - if [ -e /var/ipfire/red/active ]; then - boot_mesg "" - sysctl -w net.ipv4.tcp_syncookies=2 - sysctl -w net.ipv4.tcp_timestamps=1 - sysctl -w net.netfilter.nf_conntrack_tcp_loose=0 - /usr/sbin/xdp-loader status red0 | grep 'syncookie_xdp' - if [ $? -eq 0 ]; then - prog_id=$(xdp-loader status red0 | grep 'syncookie_xdp' | awk '{print $4}') - xdp_synproxy --prog $prog_id --ports="$ports" + if [ "$ENABLE_DDOS" == "on" ]; then + if [ -e /var/ipfire/red/active ]; then + sysctl -w net.ipv4.tcp_syncookies=2 + sysctl -w net.ipv4.tcp_timestamps=1 + sysctl -w net.netfilter.nf_conntrack_tcp_loose=0 + /usr/sbin/xdp-loader status red0 | grep 'syncookie_xdp' + if [ $? -eq 0 ]; then + prog_id=$(xdp-loader status red0 | grep 'syncookie_xdp' | awk '{print $4}') + xdp_synproxy --prog $prog_id --ports="$tcp_ports" + else + xdp-loader load red0 -m skb /usr/lib/bpf/xdp_synproxy.bpf.o + evaluate_retval + prog_id=$(/usr/sbin/xdp-loader status red0 | grep 'syncookie_xdp' | awk '{print $4}') + xdp_synproxy --prog $prog_id --ports="$tcp_ports" + fi else - xdp-loader load red0 -m skb /usr/lib/bpf/xdp_synproxy.bpf.o - evaluate_retval - prog_id=$(/usr/sbin/xdp-loader status red0 | grep 'syncookie_xdp' | awk '{print $4}') - xdp_synproxy --prog $prog_id --ports="$ports" + boot_mesg " ERROR! Red0 interface not online!" + echo_warning fi - else - boot_mesg " ERROR! Red0 interface not online!" - echo_warning fi - ;; stop)