📜 ⬆️ ⬇️

Configure PPPoE with traffic shaping for a small network

Once there was a task to set up Internet distribution for a couple of dozen computers (office and home). The boxed solutions turned out to be either paid or rather difficult to customize, so it was decided to use our own based on Debian Linux. I want to share the experience of his uplifting with you in this post, but the versions listed here could have become a little outdated since the writing of the manual “for myself”, so you need to take some care. Also, you need to take into account that the above solution is far from ideal and professional. It will help more likely those who need to quickly pick up a server that distributes the Internet. In the end, we will have Internet distribution via PPPoE with the appointment of internal IP clients, traffic shaping, DNS server and simple monitoring of current sessions from the console.


System preparation


aptitude update
aptitude install openssh-server mc mtr tracert nano tcpdump bind9 pppoe freeradius radiusclient1 rcconf php5


DNS server setup


We carry out
nano /etc/bind/named.conf.options

Add to the end of the file:
allow-transfer { none; };
allow-query { 10.128.0.0/16; localhost; }; //
allow-recursion { 10.128.0.0/16; localhost; }; //
version "My ISP DNS"; //


Let's start setting up a chroot environment for our DNS server. Create directories for the root file system of the DNS server — root-dns:
mkdir -p /root-dns/etc
mkdir /root-dns/dev
mkdir -p /root-dns/var/cache/bind
mkdir -p /root-dns/var/run/bind/run
/etc/init.d/bind9 stop
nano /etc/default/bind9


Found the line "OPTIONS =" and replaced:
OPTIONS="-u bind -t /root-dns"

mv /etc/bind /root-dns/etc
ln -s /root-dns/etc/bind /etc/bind
nano /etc/init.d/bind9

')
Found the line "OPTIONS =" and replaced:
OPTIONS="-u bind -t /root-dns"

Run:
nano /etc/init.d/rsyslogd

Found "RSYSLOGD_OPTIONS" and replaced:
RSYSLOGD_OPTIONS="-c3 -a /root-dns/dev/log"

Protect the named.conf configuration file from editing and deletion:
chattr +i /root-dns/etc/bind/named.conf

Note. Do not forget to remove the attribute “i” before editing the configuration file (chattr -i ...)

mknod /root-dns/dev/null c 1 3
mknod /root-dns/dev/random c 1 8
chmod 666 /root-dns/dev/null /root-dns/dev/random
chown -R bind:bind /root-dns/var/*
chown -R bind:bind /root-dns/etc/bind
/etc/init.d/bind9 start


PPPoE server


cd /tmp
apt-get build-dep pppoe
apt-get source pppoe
cd rp-pppoe-3.8/src
./configure


Run:
nano config.h

Now in the newly created config.h file you need to replace the line:
/* #undef HAVE_LINUX_KERNEL_PPPOE */

on line:
#define HAVE_LINUX_KERNEL_PPPOE 1

We carry out:
cd ..
./debian/rules PLUGIN_PATH=/usr/lib/pppd/2.4.4/rp-pppoe.so
./debian/rules binary
cd ..
dpkg -i pppoe_3.8-3_i386.deb


Freeze the package in the system to prevent its automatic update:
echo pppoe hold | dpkg —set-selections

From this point on, at least with each system update, you should look through the list of updates. If pppoe releases an update to close the vulnerability, it will be necessary to rebuild the fresh source package, unmute the package in the system using the command:
echo pppoe install | dpkg --set-selections

Now the system has a package with a PPPoE server installed that allows you to maintain kernel-level PPPoE connections. To start the server in this mode, add the -k option to the command described in the previous section: pppoe-server -I eth1 -L 192.168.0.1 -k

Run:
nano /etc/ppp/pppoe-server-options

Paste:
logfile /var/log/pppoe.log
debug
mtu 1472
mru 1472
auth
require-pap
#require-chap
default-asyncmap
ktune
lcp-echo-interval 20
lcp-echo-failure 2
ms-dns 10.128.0.1
plugin radius.so
plugin radattr.so
10.128.0.1:
nobsdcomp
noccp
noendpoint
noipdefault
noipx
novj
receive-all


Run:
nano /etc/ppp/options

In the / etc / ppp / options config: remove everything, set:
lock

Run:
nano /etc/init.d/pppoe-server


Script:
#!/bin/bash
# init file for rp-pppoe server
#
# description: PPPOE kernel mode server
#
# processname: pppoe-server
# chkconfig: - 45 45
# source function library
#. /etc/rc.status
case "$1" in
start)
echo -n "Starting PPPOE server: "
/usr/sbin/pppoe-server -I eth0 -L 10.128.0.1 -R 10.128.1.1 -k
# eth0 — ,
#10.128.0.1 - IP PPPoE
#10.128.1.1 - IP
#touch /var/lock/subsys/pppoed
#rc_status -v
;;
stop)
echo -n "Shutting down PPPOE server: "
pkill pppoe-server
#rm -f /var/lock/subsys/pppoed
#rc_status -v
;;
restart)
$0 stop
$0 start
;;
status)
status pppoe-server
;;
*)
echo "Usage: pppoed {start|stop|restart|status}"
exit 1
esac
exit 0


Run:
rcconf

Disable bind. Then we go in there again and see that he has disappeared altogether from the list. Below it is there, and near our pppoe-server. Turned on both this and that. Send out

cd /root-dns/etc/bind
rndc-confgen -r /dev/urandom -a
chgrp bind rndc.key
chmod +r rndc.key
nano named.conf.options


At the end of the file add:
controls {
inet 127.0.0.1 allow { localhost; } keys { rndc-key; };
};
include "/etc/bind/rndc.key";


Now, you also need to enable forvarding in the kernel and make iptables rules catch. The configuration will be test.

Parameters sysctl.conf, iptables, network interface settings


Run:
nano /etc/sysctl.conf

Uncommented, added something nebylo:
net.ipv4.conf.default.rp_filter=1
net.ipv4.conf.all.rp_filter=1
net.ipv4.tcp_syncookies=1
net.ipv4.ip_forward=1
kernel.panic = 1
kernel.panic_on_oops = 1
kernel.panic_on_io_nmi = 1
kernel.panic_on_unrecovered_nmi = 1


The last 4 lines are a reboot at various system crashes, so as not to go to reboot somewhere in another city. Save, then do the test config for iptables:
iptables -t nat -F
iptables-save > /etc/firewall.conf
nano rc.local


Now in rc.local we will have:
ifconfig eth0 up
iptables-restore </etc/firewall.conf


Further, we configure / etc / network / interfaces - here eth0 has turned out to be local, for it we don’t write anything at all, except auto eth0. And about eth1 - if this is the Internet - I would think about a static external ip, otherwise SNAT cannot be used, but only MASQUERADE, and it loads the system more.

Run:
nano /etc/network/interfaces

Config:
auto lo
iface lo inet loopback
auto eth0
auto eth1

allow-hotplug eth0 eth1
iface eth1 inet dhcp


In this listing, eth1 is the Internet via NAT and DHCP config.

PPPoE trial run


Next you need to test PPPoE without radius. To do this, we comment on 2 lines of plugins in / etc / ppp / pppoe-server-options.

Run:
nano /etc/ppp/pppoe-server-options

Config:
#plugin radius.so
#plugin radattr.so


Run:
nano /etc/ppp/pap-secrets

We add to the end or replace the entire contents:
test * test 10.128.2.10

We start pppoe-server:
/etc/init.d/pppoe-server start

Reboot the server, checked PPPoE and internet. On any client, we create a PPPoE connection and connect using the login and password test. In order for the Internet to work for the client, you need to enable masquerading:
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE

Works? Well, returned as it was:
iptables -t nat -F

Freeradius


Run:
nano /etc/radiusclient/servers

Replace the contents of the file:
127.0.0.1 my-isp-radius

Run:
nano /etc/radiusclient/radiusclient.conf

Replace the contents of the file:
auth_order radius,local
login_tries 4
login_timeout 60
nologin /etc/nologin
issue /etc/radiusclient/issue
# RADIUS settings
authserver localhost:1812
acctserver localhost:1812
servers /etc/radiusclient/servers
dictionary /etc/radiusclient/dictionary
login_radius /usr/sbin/login.radius
# RADIUS server
seqfile /var/run/radius.seq
mapfile /etc/radiusclient/port-id-map
default_realm
radius_timeout 10
radius_retries 3
login_local /bin/login


Run:
nano /etc/freeradius/radiusd.conf

Replace the contents of the file:
prefix = /usr
exec_prefix = /usr
sysconfdir = /etc
localstatedir = /var
sbindir = ${exec_prefix}/sbin
logdir = /var/log/freeradius
raddbdir = /etc/freeradius
radacctdir = ${logdir}/radacct
# .
confdir = ${raddbdir}
run_dir = ${localstatedir}/run/freeradius
# .
libdir = ${exec_prefix}/lib
# pid-. .
pidfile = ${run_dir}/freeradius.pid
# FreeRADIUS
user = freerad
group = freerad
# ( ) .
max_request_time = 30
# max_request_time
delete_blocked_requests = no
# ( ) reply NAS.
cleanup_delay = 5
# .
# 256.
# 1024.
max_requests = 5120
# ip . RADIUS
# ip .
bind_address = 127.0.0.1
# FreeRADIUS port. ,
# /etc/services
port = 0
# / ip dns .
# .
hostname_lookups = no
# / .
allow_core_dumps = no
# .
regular_expressions = yes
extended_expressions = yes
# User-Name .
log_stripped_names = no
# .
log_auth = yes
# .
# log_auth_badpass -
# log_auth_goodpass -
log_auth_badpass = yes
log_auth_goodpass = no
# / .
usercollide = no
# / .
lower_user = no
lower_pass = no
# / .
nospace_user = no
nospace_pass = no
# DoS .
security {
# RADIUS .
max_attributes = 200
# ( ) Access-Reject .
reject_delay = 1
# Status-Server
status_server = no
}
# RADIUS .
# .
$INCLUDE ${confdir}/clients.conf
# snmp .
snmp=no
# .
thread pool {
# .
start_servers = 5
# .
max_servers = 32
# .
min_spare_servers = 3
max_spare_servers = 10

# .
# RADIUS . 300,
# .
max_requests_per_server = 0
}

# .
modules {
# PAP .
# PAP .
# encryption_scheme .
# clear - .
pap {
encryption_scheme = clear
}
# CHAP .
# CHAP .
# authtype Auth-Type=CHAP
chap {
authtype = CHAP
}
# .
# .. .
preprocess {
# huntgroups - . huntgoups.
# hints - .
huntgroups = ${confdir}/huntgroups
hints = ${confdir}/hints

# Cisco VSA.
with_cisco_vsa_hack = no
}
# Microsoft CHAP .
# Microsoft CHAP v2
# authtype Auth-Type=MS-CHAP
# use_mppe = no VPN .
mschap {
authtype = MS-CHAP
use_mppe = no
}
# Livingston RADIUS .
# usersfile .
# .
# acctusersfile ().
# compat - . FreeRADIUS .
files {
usersfile = ${confdir}/users
compat = no
}

# .
detail {
detailfile = ${radacctdir}/%{Client-IP-Address}/detail-%Y%m%d
detailperm = 0600
}

# .
detail auth_log {
detailfile = ${radacctdir}/%{Client-IP-Address}/auth-detail-%Y%m%d
detailperm = 0600
}

# reply .
detail reply_log {
detailfile = ${radacctdir}/%{Client-IP-Address}/reply-detail-%Y%m%d
detailperm = 0600
}

# .
# NAS Acct-Session-ID.
# key Acct-Session-ID
acct_unique {
key = "User-Name, Acct-Session-Id, NAS-IP-Address, Client-IP-Address, NAS-Port-Id"
}

#
# cakesql.conf
#$INCLUDE ${confdir}/sql.conf
#$INCLUDE ${confdir}/sql/mysql/counter.conf
}

#
# preprocess
# .
# chap mschap chap mschap .
authorize {
preprocess
chap
mschap
# .
# auth_log
files
#sql
}
#
# , .
authenticate {
Auth-Type PAP {
pap
}

Auth-Type CHAP {
chap
}

Auth-Type MS-CHAP {
mschap
}

}
# .
preacct {
preprocess
}
# .
accounting {
# Acct-Session-Id NAS .
acct_unique
# detail .
detail
#
#sql
}
# reply-.
post-auth {
# .
reply_log
}
log {
destination = files
file = ${logdir}/radius.log
syslog_facility = daemon
stripped_names = no
auth = no
auth_badpass = no
auth_goodpass = no
}


Run:
nano /etc/freeradius/clients.conf

Replace the contents of the file:
client localhost {
ipaddr = 127.0.0.1
secret = my-isp-radius
require_message_authenticator = no
nastype = other
}


Run:
nano /etc/freeradius/users

Config:
steve Cleartext-Password := "testing"
Service-Type = Framed-User,
Framed-Protocol = PPP,
Framed-IP-Address = 10.128.13.3,
Framed-IP-Netmask = 255.255.0.0,
Framed-Routing = Broadcast-Listen,
Framed-Filter-Id = "std.ppp",
Framed-MTU = 1500,
Framed-Compression = Van-Jacobsen-TCP-IP

#

DEFAULT Framed-Protocol == PPP
Framed-Protocol = PPP,
Framed-Compression = Van-Jacobson-TCP-IP

DEFAULT Hint == "CSLIP"
Framed-Protocol = SLIP,
Framed-Compression = Van-Jacobson-TCP-IP

DEFAULT Hint == "SLIP"
Framed-Protocol = SLIP


In general, in the future you will need to configure a bundle with MySQL, but at this stage it is not critical. When adding a user, you need to restart Freeradius:
/etc/init.d/freeradius restart

Now you need to deal with traffic shaping. The idea is that the speed should be regulated individually for each user and transmitted as an attribute from the Radius server to the NAT server. What for? In order to subsequently be able to expand the structure and distribute the load across multiple NAS.

Traffic shaping


So preparation. Install the Wondershaper:
aptitude install wondershaper

This package is a single script that works with CBQ / HTB prioritization and has a reasonable call format. If desired, you can test his work before implementation:
wondershaper ppp0 512 512

Naturally, ppp0 should exist and be the result of connecting the client to our server. After the command is executed, the client's web browser can go to any site that measures speed, such as speedtest.net - and make sure that it is cut by the shaper. To reset the settings without disconnecting with the client (Kick, that is), we do
wondershaper clear ppp0

and make sure that the speed is again normal (that is, it is equal to the speed we take from the “big brother” on the WAN interface. Adding speed limits should be automated using a simple file parser /var/run/radattr.ppp* that appear when successful ppp connection and contain all the attributes transmitted by the Radius server to the PPPoE server. Let’s take care of the attributes.We supplement the contents of the additional attributes file of / etc / freeradius / dictionary with this:

Run:
nano /etc/freeradius/dictionary

Config:
# Limit session traffic
ATTRIBUTE Session-Octets-Limit 227 integer
# What to assume as limit - 0 in+out, 1 in, 2 out, 3 max(in,out)
ATTRIBUTE Octets-Direction 228 integer
# Connection Speed Limit
ATTRIBUTE PPPD-Upstream-Speed-Limit 230 integer
ATTRIBUTE PPPD-Downstream-Speed-Limit 231 integer
ATTRIBUTE PPPD-Upstream-Speed-Limit-1 232 integer
ATTRIBUTE PPPD-Downstream-Speed-Limit-1 233 integer
ATTRIBUTE PPPD-Upstream-Speed-Limit-2 234 integer
ATTRIBUTE PPPD-Downstream-Speed-Limit-2 235 integer
ATTRIBUTE PPPD-Upstream-Speed-Limit-3 236 integer
ATTRIBUTE PPPD-Downstream-Speed-Limit-3 237 integer
ATTRIBUTE Acct-Interim-Interval 85 integer


Further, the same attributes should be added to the Raduisclient dictionary. We edit / etc / radiusclient / dictionary, at the end we add the same:

Run:
nano /etc/radiusclient/dictionary

Config:
# Limit session traffic
ATTRIBUTE Session-Octets-Limit 227 integer
# What to assume as limit - 0 in+out, 1 in, 2 out, 3 max(in,out)
ATTRIBUTE Octets-Direction 228 integer
# Connection Speed Limit
ATTRIBUTE PPPD-Upstream-Speed-Limit 230 integer
ATTRIBUTE PPPD-Downstream-Speed-Limit 231 integer
ATTRIBUTE PPPD-Upstream-Speed-Limit-1 232 integer
ATTRIBUTE PPPD-Downstream-Speed-Limit-1 233 integer
ATTRIBUTE PPPD-Upstream-Speed-Limit-2 234 integer
ATTRIBUTE PPPD-Downstream-Speed-Limit-2 235 integer
ATTRIBUTE PPPD-Upstream-Speed-Limit-3 236 integer
ATTRIBUTE PPPD-Downstream-Speed-Limit-3 237 integer
ATTRIBUTE Acct-Interim-Interval 85 integer


Everything is fine, now they (FreeRadius and RadiusClient) will understand each other. Accordingly, additional lines will appear in the user settings of freeradius, indicating the limit of the incoming and outgoing speed (but not mandatory). Example / etc / freeradius / users with changes:

Run:
nano /etc/freeradius/users

Config:
steve Cleartext-Password := "testing"
Service-Type = Framed-User,
Framed-Protocol = PPP,
Framed-IP-Address = 10.128.13.3,
Framed-IP-Netmask = 255.255.0.0,
Framed-Routing = Broadcast-Listen,
Framed-Filter-Id = "std.ppp",
Framed-MTU = 1500,
Framed-Compression = Van-Jacobsen-TCP-IP
PPPD-Downstream-Speed-Limit = 1024,
PPPD-Upstream-Speed-Limit = 1024

#

DEFAULT Framed-Protocol == PPP
Framed-Protocol = PPP,
Framed-Compression = Van-Jacobson-TCP-IP

DEFAULT Hint == "CSLIP"
Framed-Protocol = SLIP,
Framed-Compression = Van-Jacobson-TCP-IP

DEFAULT Hint == "SLIP"
Framed-Protocol = SLIP


Now the NAS receives information about the speed, but can not handle them. We make two scripts that perform the parsing of the transferred attributes when establishing a connection:

Run:
nano /etc/ppp/ip-up.d/0001shaper

Script:
#!/bin/sh
/root-scripts/shape-on $1 $5
exit 0


Run:
nano /etc/ppp/ip-down.d/0001shaper

Script:
#!/bin/sh
/root-scripts/shape-off $1 $5
exit 0


As you can see from these listings, some script is called that applies and cancels the shaping. From this point on - in more detail. $ 1 is the transferred interface name, that is, ppp0 for example, $ 5 is Framed-IP, that is, the PPP client IP. Create a coveted directory and put two files into it:
mkdir /root-scripts
nano /root-scripts/shape-on


Script:
#!/bin/sh
if [ -f /var/run/radattr.$1 ]
then
DOWNSPEED=`awk '/PPPD-Downstream-Speed-Limit/ {print $2}' /var/run/radattr.$1`
UPSPEED=`awk '/PPPD-Upstream-Speed-Limit/ {print $2}' /var/run/radattr.$1`
wondershaper $1 $DOWNSPEED $UPSPEED
fi
iptables -A FORWARD -s $2 -j ACCEPT
iptables -A INPUT -s $2 -j ACCEPT
iptables -t nat -A POSTROUTING -s $2 -o eth1 -j MASQUERADE


Run:
nano /root-scripts/shape-off

Script:
#!/bin/sh
iptables -D FORWARD -s $2 -j ACCEPT
iptables -D INPUT -s $2 -j ACCEPT
iptables -t nat -D POSTROUTING -s $2 -o eth1 -j MASQUERADE


Run:
chmod +x /root-scripts/*

In eth1 listings, this is still the WAN interface. So, what we get as a result: The client connects to the PPP server, gets an IP address. A script is automatically called that configures shaping on the client PPP interface and enables masquerading for it. When disconnecting the masquerading rule is also removed automatically. It seems like the wondershaper does not need to be forcibly uncoupled from pppx, in any case, the manuals are silent about this and everything works fine in practice.

Simple iptables based protection


Now let's pay a little attention to iptables and server security. Replace /etc/firewall.conf:

Run:
nano /etc/firewall.conf

Script:
#!/bin/bash

#reset all
iptables -F
iptables -Z
iptables -t nat -F
iptables -t nat -Z

#iface config
INET_IFACE="eth1"
LO_IFACE="lo"
LO_IP="127.0.0.1"

#kernel modules
modprobe ip_tables
modprobe ip_conntrack
modprobe iptable_filter
modprobe iptable_mangle
modprobe iptable_nat
modprobe ipt_LOG
modprobe ipt_limit
modprobe ipt_state
modprobe ipt_MASQUERADE
modprobe ip_conntrack_ftp
modprobe ip_conntrack_irc
modprobe ip_nat_ftp
modprobe ip_nat_irc

#default policy
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP

#user chains
iptables -N bad_tcp_packets
iptables -N allowed
iptables -N tcp_packets
iptables -N udp_packets
iptables -N icmp_packets
iptables -N blocksshd
blocksshd --start

###bad_tcp_packets chain
iptables -A bad_tcp_packets -p tcp --tcp-flags SYN,ACK SYN,ACK -m state --state NEW -j REJECT --reject-with tcp-reset
#iptables -A bad_tcp_packets -p tcp ! --syn -m state --state NEW -j LOG --log-prefix "New not syn:"
iptables -A bad_tcp_packets -p tcp ! --syn -m state --state NEW -j DROP

###allowed chain
iptables -A allowed -p TCP --syn -j ACCEPT
iptables -A allowed -p TCP -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A allowed -p TCP -j DROP

###tcp_packets chain
iptables -A tcp_packets -p TCP -s 0/0 --dport 22 -j blocksshd
iptables -A tcp_packets -p TCP -s 0/0 --dport 22 -j allowed
iptables -A tcp_packets -p TCP -s 0/0 --dport 25 -j allowed
#iptables -A tcp_packets -p TCP -s 0/0 --dport 80 -j allowed

###udp_packets chain
iptables -A udp_packets -p UDP -s 0/0 --destination-port 53 -j ACCEPT

###icmp chain
iptables -A icmp_packets -p ICMP -s 0/0 --icmp-type 8 -j ACCEPT
iptables -A icmp_packets -p ICMP -s 0/0 --icmp-type 11 -j ACCEPT

###input chain
iptables -A INPUT -p TCP -j bad_tcp_packets
iptables -A INPUT -p ALL -i $LO_IFACE -j ACCEPT
iptables -A INPUT -p ALL -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p TCP -i $INET_IFACE -j tcp_packets
iptables -A INPUT -p UDP -i $INET_IFACE -j udp_packets
iptables -A INPUT -p ICMP -i $INET_IFACE -j icmp_packets
#iptables -A INPUT -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level DEBUG --log-prefix "IPT INPUT packet died: "

###forward chain
iptables -A FORWARD -p tcp -j bad_tcp_packets
#custom rules
#iptables -A FORWARD -s 10.128.0.10/32 -d 192.168.1.1/32 -p tcp -j ACCEPT
iptables -A FORWARD -s 10.128.0.0/16 -d 192.168.1.1/32 -p tcp -j DROP
#/custom rules
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
#iptables -A FORWARD -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level DEBUG --log-prefix "IPT FORWARD packet died: "

###OUTPUT chain
iptables -A OUTPUT -p tcp -j bad_tcp_packets
iptables -A OUTPUT -p ALL -j ACCEPT
#iptables -A OUTPUT -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level DEBUG --log-prefix "IPT OUTPUT packet died: "

###mangle
iptables -t mangle -A POSTROUTING -o $INET_IFACE -j TTL --ttl-set 64


What do we see here? First, the highlighted rule. It will differ in the actual configuration or simply be absent as unnecessary, but the point is this: if the gateway for the server is an ADSL modem or similar device with a web admin area, we do not need to invent clever passwords to enter there. Instead, we prohibit access to them from client tunnels, but we still allow one thing - it will be a service account with which you can break into it. Of course, it is not for customers. Further. Commands including protection against SSH server bruteforcing have been added. For their work, you need to configure blocksshd.

BlockSSHd


First you need to download it from blocksshd.sourceforge.net and unzip files somewhere. I used to download wget, but the way - of course - cut from the page of SourceForge, that is, it will most likely be different:
cd /tmp
wget downloads.sourceforge.net/project/blocksshd/blocksshd/BlockSSHD%201.3/blocksshd-1.3.tar.gz?use_mirror=kent


This script is written in Perl and requires some additional modules to work. So, let's do the modules:
cpan
upgrade
install Sys::Syslog
install Sys::Hostname
install File::Tail
install Tie::File
install Net::DNS
install Net::Subnets
install Getopt::Long
exit


I draw attention to the fact that all this in one fell swoop does not need to copy and paste into the terminal. This is because each operation takes a lot of time to complete and during the entire installation Cpan will ask questions. All questions can simply press Enter, there everything is correct by default, oddly enough.

Now you need to unpack the blocksshd and install it:
cd /tmp
tar -xvzf ./blocksshd-1.3.tar.gz
cd blocksshd-1.3
make install


And of course, the version at the time of writing the manual was this one, and maybe any, so you need to carefully do everything and not copy-paste to the console. It remains to edit the blocksshd configuration:

Run:
nano /etc/blocksshd.conf

Config:
$cfg = {
os => 'linux', # Target OS - either linux or bsd
chain => 'blocksshd', # Name of iptables or pf chain
logfile => '/var/log/secure', # Log file to monitor
logcheck => '10', # How often to check the log file
max_attempts => '4', # Max number of failures
timeout => '360', # Reset IP count if no activity after time out in seconds
unblock => '1', # Enable unblocking
unblock_timeout => '43200', # Time in seconds after which to unblock a blocked IP address
restore_blocked => '0', # Turn on checking for previously blocked IPs
log_ips => '/etc/blocksshd.list', # Log file for blocked IPs
pid_file => '/var/run/blocksshd.pid', # Location of PID file
send_email => '0', # Enable the sending of email notifications
email => 'root', # Email address to send notifications
mail => '/bin/mail', # Location of mail binary
email_whois_lookup => '1', # enable whois lookup of the blocked ip addres in the sent email
whois => '/usr/bin/whois', # location of the whois binary
sed => '/bin/sed', # location of the sed binary
iptables => '/sbin/iptables', # Location of iptables binary - only for Linux
pfctl => '/sbin/pfctl', # Location of pfctl binary - only for BSD
whitelist => [qw{
127.0.0.1/32
}], # whitelist - list of IPs that will never be blocked - IPs must be specified in the form ad$
};

#leave 1; here!
1;


In this listing you need to pay attention to the selected lines. The first is the maximum number of attempts to log in from one address, the second is whether it is necessary to unblock a banned ip after the time in seconds specified in the third line has elapsed. Fourth - whether to notify by email about hacking attempts.
Now you can restart the server and test what happened.

Simplest monitoring


For the convenience of monitoring active sessions, you can use a script written “on the knee”. We will create it and set up a simlink for a simple launch, and of course we will check:

Run:
nano /root-scripts/clients

Script:
#!/usr/bin/php
<?
function time_since($original) {
$chunks = array(
array(60 * 60 * 24 , 'D '),
array(60 * 60 , 'h:'),
array(60 , 'min'),
);
$today = time();
$since = $today - $original;
for ($i = 0, $j = count($chunks); $i < $j; $i++) {
$seconds = $chunks[$i][0];
$name = $chunks[$i][1];
if (($count = floor($since / $seconds)) != 0) {
break;
}
}
$print = "$count{$name}";
if ($i + 1 < $j) {
$seconds2 = $chunks[$i + 1][0];
$name2 = $chunks[$i + 1][1];
if (($count2 = floor(($since - ($seconds * $count)) / $seconds2)) != 0) {
$print .= "$count2{$name2}";
}
}
return $print;
}

function execShellCmdRaw($cmd) {
ob_start();
passthru($cmd);
$buffer = ob_get_contents();
ob_end_clean();
return $buffer;
}

function rawToArray($buffer) {
return empty($buffer)?array():preg_split('/[\r\n]+/', $buffer, -1, PREG_SPLIT_NO_EMPTY);
}

function execShellCmd($cmd) {
return rawToArray(execShellCmdRaw($cmd));
}

function getNATSources() {
$nat = execShellCmd('iptables -t nat -L | grep MASQUERADE');
$nats = array();
foreach ($nat as $s) {
$pos_start = strpos($s, '--') + 2;
$pos_end = strpos($s, 'anywhere');
$n = trim(substr($s, $pos_start, $pos_end - $pos_start));
$nats[$n] = $n;
}
return $nats;
}

function getTunnelMacAddr($pid) {
$pppdc = execShellCmd('ps -p '.$pid.' -f | grep pppd');
$pppdc = $pppdc[0];
$pos_start = strpos($pppdc, '-e ') + 3;
$pos_end = strpos($pppdc, '-S \'\'');
return trim(substr($pppdc, $pos_start, $pos_end - $pos_start));
}

function getPPPTunnels() {
$ifc = execShellCmd('ifconfig -a');
$tunnels = array();
$nat = getNATSources();
foreach ($ifc as $i => $s) {
if (substr($s, 0, 3) == 'ppp') {
$ppp = array();
$ppp['interface'] = substr($s, 0, 4);
$ppp['framed_ip'] = trim(substr($ifc[$i+1], strpos($ifc[$i+1], 'PtP:') + 6, 12));
$RXpos_start = strpos($ifc[$i+6], '(') + 1;
$RXpos_end = strpos($ifc[$i+6], ')');
$ppp['tx'] = substr($ifc[$i+6], $RXpos_start, $RXpos_end - $RXpos_start); //TX(user) = RX(server)
$tx_sub = substr($ifc[$i+6], $RXpos_end + 1);
$TXpos_start = strpos($tx_sub, '(') + 1;
$TXpos_end = strpos($tx_sub, ')');
$ppp['rx'] = substr($tx_sub, $TXpos_start, $TXpos_end - $TXpos_start);
$ppp['nat'] = array_key_exists($ppp['framed_ip'], $nat)?'on':'off';
$pidf = '/var/run/'.$ppp['interface'].'.pid';
if (file_exists($pidf)) {
$ppp['uptime'] = time_since(filemtime($pidf));
$ppp['pid'] = trim(file_get_contents($pidf));
$ppp['mac_addr'] = getTunnelMacAddr($ppp['pid']);
$ppp['username'] = 'detectedusername';
$tunnels[] = $ppp;
}
}
}
return $tunnels;
}

function clientTable($tunnels) {
printf("\n");
printf(" %15s | ","IP Address");
printf("%20s | ","MAC Address ");
printf("%3s | ","NAT");
printf("%16s | ","User name ");
printf("%9s | ","TX (up)");
printf("%9s | ","RX (down)");
printf("%11s","Uptime ");
printf("\n ");
for ($i = 0; $i < 101; $i++) printf("-");
printf("\n");
foreach($tunnels as $tun) {
printf(" %15s | ",$tun['framed_ip']);
printf("%20s | ",$tun['mac_addr']);
printf("%3s | ",$tun['nat']);
printf("%16s | ",$tun['username']);
printf("%9s | ",$tun['tx']);
printf("%9s | ",$tun['rx']);
printf("%11s",$tun['uptime']);
printf("\n");
}
printf("\n");
}

function addRadParams(&$tunnels = NULL) {
$radusers = rawToArray(file_get_contents('/etc/freeradius/users'));
$users = array();
foreach ($radusers as $i => $s) {
if (strpos($s, 'Cleartext-Password') !== FALSE) {
$user = array();
$user['username'] = trim(substr($s, 0, strpos($s, 'Cleartext-Password')));
$si = $i + 1;
while (strpos($radusers[$si], 'Framed-IP-Address') == FALSE) $si++;
$ip_raw = explode('=', $radusers[$si]);
$ip_raw = $ip_raw[1];
$users[trim($ip_raw, ' ,')] = $user;
}
}
foreach ($tunnels as $i => $tun) {
$tunnels[$i]['username'] = $users[$tun['framed_ip']]['username'];
}
return $tunnels;
}

$t = getPPPTunnels();
addRadParams($t);
clientTable($t);


Run:
chmod +x /root-scripts/clients
ln -s /root-scripts/clients /usr/bin/clients
clients


We get something like:

IP Address | MAC Address | NAT | User name | TX (up) | RX (down) | Uptime
-----------------------------------------------------------------------------------------------------
10.128.1.7 | 1:00:19:66:df:39:26 | on | room56 | 507.4 MiB | 445.5 MiB | 16h:31min
10.128.1.3 | 23:00:13:8f:70:30:03 | on | room47 | 8.2 MiB | 137.8 MiB | 1h:14min
10.128.1.5 | 3:00:a1:b0:11:74:cf | on | room50 | 19.2 MiB | 500.2 MiB | 16h:30min


That's all, our server is ready to use. According to my observations, I can say that a simple system unit with 1 GB of DDR1 and 2 GHz processor is enough to distribute a 16-megabit channel for 30 users (it was just not needed anymore) and the system does not experience a significant load.

Good luck to novice providers!

Source: https://habr.com/ru/post/111399/


All Articles