54
Managing Internet Connections With PPPoE, MikroTik and Radius           Dashamir Hoxha      <[email protected] >           Artur Nurja                <[email protected] > Copyright (C) 2009 Dashamir Hoxha, Artur Nurja. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License." 1 Abstract This article will describe how to manage internet clients of an ISP with PPPoE and MikroTik. For centralized AAA (Authentication, Authorization and Accounting), freeRadius is used. This article is based on the work that we have done at AlbaniaOnline ISP (now called Primo). 2 Introduction The aim of the project was to give PPPoE service to the internet clients, through MikroTik. This is not difficult and can be implemented easily, however we would like to use freeRadius for AAA, so that we could keep the data of the clients and their settings in a database. MikroTik should be just a dummy box with a simple configuration, so that we can throw it away and replace it by another one at anytime. All the client data (username, password, connection settings etc.) should be stored in the freeRadius database. If they are in a database the client data can be managed easily by an external application as well (by integrating the freeRadius database with the application). 2.1 Observations About Implementation Possibilities Digging into the manual pages of MikroTik, freeRadius, etc. and making experiments, we made these observations about the different ways a PPPoE service can be implemented with MikroTik and Radius: There can be more than one MikroTik servers in a LAN. In a MikroTik server we can run more than one PPPoE service (with different names and profiles). Each of the PPPoE services can authenticate the internet users using one or more Radius servers. The MikroTik consults the radius server about authenticating a PPPoE user only if this user is not in his local database. A freeRadius server can use one or more MySQL databases for authenticating a user. If it cannot 

PPPoE With Mikrotik and Radius

Embed Size (px)

DESCRIPTION

How to manage internet clients of an ISP with PPPoE and MikroTik. For centralized AAA (Authentication, Authorization and Accounting), freeRadius is used.

Citation preview

Page 1: PPPoE With Mikrotik and Radius

Managing Internet Connections With 

PPPoE, MikroTik and Radius

          Dashamir Hoxha      <[email protected]>

          Artur Nurja                <[email protected]>

Copyright (C) 2009 Dashamir Hoxha, Artur Nurja. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License."

1 Abstract

This article will describe how to manage internet clients of an ISP with PPPoE and MikroTik. For centralized AAA (Authentication, Authorization and Accounting), freeRadius is used. This article is based on the work that we have done at AlbaniaOnline ISP (now called Primo).

2 Introduction

The aim of the project was to give PPPoE service to the internet clients, through MikroTik. This is not difficult and can be implemented easily, however we would like to use freeRadius for AAA, so that we could keep the data of the clients and their settings in a database. MikroTik should be just a dummy box with a simple configuration, so that we can throw it away and replace it by another one at anytime. All the client data (username, password, connection settings etc.) should be stored in the freeRadius database. If they are in a database the client data can be managed easily by an external application as well (by integrating the freeRadius database with the application). 

2.1 Observations About Implementation Possibilities

Digging into the manual pages of MikroTik, freeRadius, etc. and making experiments, we made these observations about the different ways a PPPoE service can be implemented with MikroTik and Radius:

● There can be more than one MikroTik servers in a LAN.

● In a MikroTik server we can run more than one PPPoE service (with different names and profiles).

● Each of the PPPoE services can authenticate the internet users using one or more Radius servers.

● The MikroTik consults the radius server about authenticating a PPPoE user only if this user is not in his local database. 

● A freeRadius server can use one or more MySQL databases for authenticating a user. If it cannot 

Page 2: PPPoE With Mikrotik and Radius

connect to one database, then it switches to another.

● A freeRadius server can act as proxy, getting the answer from another radius server. It can use more than one radius server for getting the answer and can do even load­balancing between them, in case that they are the same (are used for the same thing). 

● The attributes of the Internet connection of a client (IP, GW, DNS, bandwidth, etc.) can be defined in the radius database or in the profile of the client in MikroTik.

● In the freeRadius database, the connection attributes can be set for each client or for the group to which the client belongs.

● IP­s that are assigned to the clients can be random (from an IP pool) or each client can be assigned a fixed IP, always the same IP no matter to which MikroTik it is connected.

● The MikroTik gateway server can connect the clients to the Internet using IP­proxy (NAT) or using ARP­proxy.

2.2 The Architecture of The PPPoE Service

Based on the above observations and on the project goals, we decided to construct the PPPoE service infrastructure like this:

● For client authentication we should use 2 freeRadius servers. Each of them will query its own MySQL database and these databases will replicate with each­other (one of them as primary and the other one as secondary). 

The advantages of using two radius servers instead of one, are these:

● Half of the requests will be handled by one and half will be handled by the other, so, we will have load­balancing.

● If one of them is not working properly, the other one will handle all the requests and the service will not be interrupted. This provides high availability of the service (the service is more stable).

● They also serve as a backup of each­other. If the database of one of them is damaged, the data can be restored from the other.

● The external application that keeps  the client data will be connected to the radius database (only to the primary one) and will manage the client  data there.

● To manage the client connections, 3­4 or more MikroTik servers can be used. Each of them has the same configuration and they are connected in the same hub/switch with the clients. Since the clients connect randomly to each of them, we are going to have load­balancing between the MikroTik servers. In general, each of the MikroTik servers can serve up to 400­500 clients simultaneously. 

● MikroTik gateways will authenticate the clients by asking the radius servers. Each of them will have two radius servers in its configuration. Half of them ask first radius1 and if they get no answer they ask radius2. The other half ask first radius2. This provides load­balancing for the radius servers.

Page 3: PPPoE With Mikrotik and Radius

● The clients are connected to the Internet through IP­proxy (NAT).

● The IP that is assigned to the clients are random, taken from an IP pool (they are not fixed IP­s).

3 Installing And Configuring freeRadius, MySQL and MikroTik

3.1 Installing freeRadius

We installed freeRadius on Fedora7. First I installed the packages freeradius and freeradius­mysql : 

bash# yum install freeradius freeradius-mysql

Then I enabled the service radiusd and started it: 

bash# /sbin/chkconfig --list radiusdbash# /sbin/chkconfig radiusd onbash# /sbin/chkconfig --list radiusd

bash# /sbin/service radiusd start

Since freeradius uses the ports 1812 and 1813 (see e.g. the file /etc/services ), I had to open these ports in the firewall, both for tcp and udp . In order to do this, I edited the file /etc/sysconfig/iptables and added there these lines: 

-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 1812 -j ACCEPT-A RH-Firewall-1-INPUT -m udp -p udp --dport 1812 -j ACCEPT-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 1813 -j ACCEPT-A RH-Firewall-1-INPUT -m udp -p udp --dport 1813 -j ACCEPT

To apply these modifications in firewall, I restarted the service iptables: 

bash# /sbin/service iptables restart

Tip: To check that the ports 1812 and 1813 are open in the firewall, we can use one of these commands: 

bash# /sbin/service iptables status | grep 1812bash# /sbin/iptables-save | grep 1812

3.2 Testing freeRadius Installation

Just to test that freeRadius is correctly installed and works, we can make a simple configuration using the standard text files, like this: 

Edit the file /etc/raddb/clients.conf . At the section client 127.0.0.1 modify the value of secret , for example make it local1 . The entry 

client 127.0.0.1

Page 4: PPPoE With Mikrotik and Radius

{ . . . }

will allow the localhost to use the radius service. 

Edit the file /etc/raddb/users . Uncomment there the test user steve (or create another user with similar details). It should look like this: 

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

Edit /etc/raddb/radiusd.conf and make sure that authorization using files is enabled. (It should be enabled by default, so in general you don't need to modify anything.) 

Now we can use the command radtest to request access for user steve with password testing : 

bash# radtest --helpbash# radtest steve testing 127.0.0.1 10 local1bash# radtest steve testing localhost 10 local1bash# radtest steve testingX 127.0.0.1 10 local1bash# radtest steve testing 127.0.0.1 10 local1X

In the first and second tests you should get the answer 'Access­Accept'. In the last two tests you should get the answer 'Access­Reject'. 

Tip: In order to get more details about what happens in the server, run radiusd in debug mode. First stop the service: /sbin/service radiusd stop , then run it like this: /usr/sbin/radiusd ­x or /usr/sbin/radiusd ­X .

Note: If you have Windows, you may also wish to use NTradPing (downloadable from MasterSoft ) instead of radtest. If you do this, or test from any other machine, remember to put your PC (or the other machine) in your NAS list in the file /etc/raddb/clients.conf .

3.3 Set Up freeRadius to Use a MySQL Database

Now that radius is installed and we have tested that it works correctly, we can create a mysql database for it and configure radius to use this database. 

First let's create a new database and a new database user: 

bash$ mysql -p -u rootmysql> CREATE DATABASE radiusdb;mysql> GRANT ALL ON radiusdb.* TO raduser@localhost IDENTIFIED BY "radpass";mysql> exit;

Page 5: PPPoE With Mikrotik and Radius

Now lets create the tables of the database by running the SQL script file that is in the directory freeradius/doc/examples/: 

bash$ mysql -p -u root -D radiusdb < /usr/share/doc/freeradius-1.1.7/examples/mysql.sql

We should modify now /etc/raddb/sql.conf by setting there the database, the username and the password that are needed to connect to the mysql server: 

# Connect info server = "localhost" login = "raduser" password = "radpass"

# Database table configuration radius_db = "radiusdb"

Note: For testing/debug purposes, change sqltrace to yes. Then, freeradius will dump all SQL commands to the debug output.Note: You may also need to modify the line about sql_user_name in this file.

Edit the file /etc/raddb/radiusd.conf and make there these modifications: 

Uncomment the line saying 'sql' in the authorize{} section and comment the line saying 'files'. 

Also uncomment the line saying 'sql' to the accounting{} section to tell FreeRADIUS to store accounting records in SQL as well. This file should then look something like this: 

authorise { preprocess chap mschap suffix eap # files sql pap}

accounting { # We leave "detail" enabled to _additionally_ log accounting to /var/log/radius/radacct detail sql}

3.4 Testing MySQL

Enter some data into the database: 

bash$ mysql -u raduser -p radpasswmysql> USE radiusdb;mysql> SHOW TABLES;

Page 6: PPPoE With Mikrotik and Radius

mysql> INSERT INTO usergroup (UserName, GroupName) --> VALUES ("radiustest", "testgroup");mysql> SELECT * FROM usergroup;mysql> INSERT INTO radcheck (UserName, Attribute, Value) --> VALUES ("radiustest", "Password", "testpassword");mysql> SELECT * FROM radcheck;mysql> INSERT INTO radgroupreply (GroupName, Attribute, op, Value) --> VALUES ("testgroup","Framed-Compression","==","Van-Jacobsen-TCP-IP");mysql> INSERT INTO radgroupreply (GroupName, Attribute, op, Value) --> VALUES ("testgroup","Framed-Protocol","==","PPP");mysql> INSERT INTO radgroupreply (GroupName, Attribute, op, Value) --> VALUES ("testgroup","Framed-MTU","==","1500");mysql> INSERT INTO radgroupreply (GroupName, Attribute, op, Value) --> VALUES ("testgroup","Service-Type","==","Framed-User");mysql> quit;

Then stop the service /sbin/service radiusd stop and run radiusd in debug mode: /usr/sbin/radiusd ­x or /usr/sbin/radiusd ­X . 

Now check access for the user radiustest with password testpassword : 

bash# radtest radiustest testpassword localhost 10 local1Sending Access-Request of id 224 to 127.0.0.1 port 1812 User-Name = "radiustest" User-Password = "testpassword" NAS-IP-Address = 255.255.255.255 NAS-Port = 10rad_recv: Access-Accept packet from host 127.0.0.1:1812, id=224, length=44 Framed-Compression = Van-Jacobson-TCP-IP Framed-Protocol = PPP Framed-MTU = 1500 Service-Type = Framed-User

3.5 Configure MikroTik for Being a PPPoE Server

First, the package PPP needs to be installed in MikroTik. 

Now let us suppose that ether1 is connected to WAN and ether2 is connected to LAN. Then add an IP address to ether1, add a gateway, DNS etc. so that the MikroTik box can connect to internet. 

Important: Do not add an IP address to the internal interface (ether2).

If NAT is used, ensure that src­nat/masquerade firewall rule has been added ( /ip firewall nat ... ) and it is working properly. It can be added like this: 

> /ip firewall nat add chain=srcnat out-interface=ether1 action=masquerade

Test the connection of the MikroTik server to internet: 

> /ping www.google.com

Once you have verified the server’s connectivity, create PPP profiles: 

Page 7: PPPoE With Mikrotik and Radius

> /ppp profile add name="pppoe-128k" local-address=10.10.1.1 dns-server="192.168.25.101" rate-limit=128k/128k> /ppp profile add name="pppoe-256k" local-address=10.10.1.1 dns-server="192.168.25.101" rate-limit=256k/256k

These two profiles have different connection speeds. 

Now create a PPPoE server instance (service) and enable it: 

> /interface pppoe-server server add service-name="pppoe1" \ interface=ether2 \ one-session-per-host=yes default-profile="pppoe-128k"> /interface pppoe-server server print> /interface pppoe-server enable 0

Finally create user accounts: 

> /ppp secret add name="test128" password="test128" service=pppoe \ profile="pppoe-128k" remote-address=10.10.1.111> /ppp secret add name="test256" password="test256" service=pppoe \ profile="pppoe-256k" remote-address=10.10.1.112> ppp secret printFlags: X - disabled # NAME SERVICE CALLER-ID PASSWORD PROFILE REMOTE-ADDRESS 0 test128 pppoe test128 pppoe-128k 10.10.1.111 1 test256 pppoe test256 pppoe-256k 10.10.1.112

Now the PPPoE server is ready to answer PPPoE requests and to authenticate PPPoE clients. 

Important: We don't need to give an IP address to ether2 (the interface that is on the clients' side) for PPPoE to work. The PPPoE will assign automatically to the interface a new IP (which is like 10.10.1.1/32 in our example). So, a new virtual IP will be assigned to the interface for each client that is connected to the server. If we assign an IP address to ether2, then the clients can connect to the internet using ethernet instead of using pppoe. In general this is not what we want, because the ethernet connections do not require a username and password and their bandwidth cannot be limited as easily as pppoe connections.

3.6 Testing the PPPoE Service

To configure a windows computer to connect as a PPPoE client, do these: 

Open the "New Connection Wizard" (from Network Connections). 

In the next window (Network Connection Type) choose "Connect to the Internet". 

In the next window (Getting Ready) select the choice "Set up my connection manually". 

In the next step of the wizard (Internet Connection), select "Connect using a broadband connection that requires a username and password". 

Then, in the next window (Connection Name), write a name for the connection, something like "PPPoE". 

Next, give the username and password, for example username: test256 , password: test256 . 

Page 8: PPPoE With Mikrotik and Radius

Finally finish the wizard. Now you should have a new connection at the Network Connections. 

To configure a Fedora7 computer to connect as a PPPoE client, follow these steps: 

From the menus, open System > Administration > Network . You have to give the root password in order to access this menu. 

Create a new connection and select connection type xDSL. 

Give username, password, etc. 

Activate the new connection. 

3.7 Getting MikroTik to Work with RADIUS

Right now we have a MikroTik that is configured as a PPPoE server and we have a freeRadius server that is configured to check the data in a MySQL database. Now we need to configure MikroTik to use the radius server for authenticating users. We also need to enter in the database of radius the data of the clients (username, password and connection properties). Let's see how these can be done. 

In MikroTik, add a radius server for the service ppp : 

> /radius add service=ppp address=192.168.25.101 secret=mikro1

The IP of the radius server is 192.168.25.101 and it will be used for authenticating PPPoE clients (users of service ppp ). The secret is like a password that the MikroTik and radius servers use to verify each­other. 

Tell the ppp service to use radius for AAA (Authentication, Authorization and Accounting): 

> /ppp aaa set use-radius=yes> /ppp aaa print

In the radius server, make sure that the configuration file /etc/raddb/clients.conf contains a section like this: 

client 192.168.25.1 { secret = mikro1 shortname = MikroTik1}

Then restart the radius service.

Make sure that the user test256 is not authenticated in the ppp service of MikroTik (or remove it if it is there): 

> /ppp secret print> /ppp secret remove 1

Check and make sure that the client test256 cannot connect to internet using the PPPoE 

Page 9: PPPoE With Mikrotik and Radius

connection. 

Now lets add some data about the user test256 in the mysql database of radius: 

bash$ mysql -p -u rootmysql> show databases;mysql> use radius;mysql> show tables;mysql> insert into usergroup (Username, GroupName) values ('test256', 'static256');mysql> select * from usergroup where username='test256';+------------+-----------+----------+| UserName | GroupName | priority |+------------+-----------+----------+| test256 | static256 | 1 |+------------+-----------+----------+1 row in set (0.02 sec)

mysql> insert into radcheck (Username, Attribute, Value, Op) --> values ('test256', 'Cleartext-Password', 'test256', ":=");mysql> select * from radcheck where username='test256';+----+----------+--------------------+----+----------+| id | UserName | Attribute | op | Value |+----+----------+--------------------+----+----------+| 2 | test256 | Cleartext-Password | := | test256 |+----+----------+--------------------+----+----------+1 row in set (0.00 sec)

mysql> insert into radreply (UserName, Attribute, Value, Op) --> values ('test256', 'Framed-IP-Address', '192.168.10.101', ':=');mysql> select * from radreply where username='test256';+----+----------+-------------------+----+----------------+| id | UserName | Attribute | op | Value |+----+----------+-------------------+----+----------------+| 1 | test256 | Framed-IP-Address | := | 192.168.10.101 |+----+----------+-------------------+----+----------------+1 row in set (0.02 sec)

mysql> insert into radgroupreply (GroupName, Attribute, Value, Op) --> values ('static256', 'Framed-Protocol', 'PPP', ':=');mysql> insert into radgroupreply (GroupName, Attribute, Value, Op) --> values ('static256', 'Service-Type', 'Framed-User', ':=');mysql> insert into radgroupreply (GroupName, Attribute, Value, Op) --> values ('static256', 'Framed-Compression', 'Van-Jacobsen-TCP-IP', ':=');mysql> select * from radgroupreply where groupname='static256';+----+-----------+--------------------+----+---------------------+| id | GroupName | Attribute | op | Value |+----+-----------+--------------------+----+---------------------+| 5 | static256 | Framed-Protocol | := | PPP || 6 | static256 | Service-Type | := | Framed-User || 7 | static256 | Framed-Compression | := | Van-Jacobsen-TCP-IP |+----+-----------+--------------------+----+---------------------+3 rows in set (0.00 sec)

If you try now to connect to internet as a client with username 'test256' and password 'test256', using PPPoE, it should work. However, to make sure that it really works through radius authentication, which gets the authentication data from the database, you can stop the radiusd service (in the radius server) and run it in debug mode: /usr/sbin/radiusd ­x . 

Page 10: PPPoE With Mikrotik and Radius

4 Using Two Radius Servers

4.1 Adding a Second Radius Server in MikroTik

MikroTik can be configured to use more than one radius server for the authentication of the users. It is done simply by adding additional radius servers: 

> /radius add service=ppp address=192.168.25.101 secret=mikro1 > /radius add service=ppp address=192.168.25.102 secret=mikro1 > /radius print Flags: X - disabled # SERVICE CALLED-ID DOMAIN ADDRESS SECRET 0 ppp 192.168.25.101 mikro1 1 ppp 192.168.25.102 mikro1

In this case, MikroTik tries to use the first server for authentication, and if it cannot be connected, tries the second one. This make the service of Radius more robust (if one server is down, there is still the other one). 

The configuration of the second radius server is the same as the first one. Both of their MySQL databases replicate with each­other (two­way, bidirectional replication), so that both of them can be used at the same time and they can synchronize the data automatically.

Since both of the servers can be used at the same time (and they synchronize with each­other), then we can have a kind of load balancing by configuring half of the MikroTik servers to have one radius server as primary, and the other half to have the other server as primary in the list. 

So, this redundancy of the radius servers ensures both high­availability and load balancing. 

4.2 Replicating MySQL Databases of Radius

In order to ensure service backup, high availability and load balancing, we replicate the databases of the radius servers. We do it a two­way replication, so that both of them can be used for reading and writing, and so that in case that one of them goes off, we don't need to do any manual configuration. 

The two­way replication can be done like this: 

1. In both servers modify the section [mysqld] in the configuration file /etc/my.cnf and add these lines: 

### configuration as a master for replicationserver-id=1log-bin=mysql_bininnodb_flush_log_at_trx_commit=1sync_binlog=1slave-skip-errors=allauto_increment_offset=1auto_increment_increment=10

Make sure the servers have unique (different) server IDs, that skip­networking is not set, and that binary logging is enabled. Also make sure that auto_increment_offset is different for each server. (For the meaning of these options check the manual of mysql.) 

Page 11: PPPoE With Mikrotik and Radius

2. In the first server create a user that has permission to do replication: 

mysql> GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'192.168.25.%' --> IDENTIFIED BY 'replpassw';mysql> FLUSH PRIVILEGES;

3. Make a full backup of the mysql database in the first server: 

/usr/bin/mysqldump --user=root --password --all-databases \ --lock-all-tables --flush-logs --flush-privileges \ --add-drop-database --add-drop-table \ --force --master-data > backup.sql

4. Copy it to the other server and restore it: 

bash# scp [email protected]:backup.sql .bash# /sbin/service mysqld startbash# mysql -p -u root < backup.sql

5. Setup the second server as slave and start the replication in it: 

mysql> CHANGE MASTER TO MASTER_HOST='192.168.25.101', MASTER_USER='repluser', MASTER_PASSWORD='replpassw';mysql> START SLAVE;mysql> show slave status\G

The options MASTER_LOG_FILE and MASTER_LOG_POS can be given to CHANGE MASTER TO as well, however they are restored from the backup file (since mysqldump was called with the option ­­master­data). If you want to add them manually, then read their values from the backup file backup.sql .

6. Setup also the first server as a slave of the first master. 

a. In the second server (that will be master of the first one), get the status of the master: 

mysql> show master status;+------------------+----------+--------------+------------------+| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |+------------------+----------+--------------+------------------+| mysql_bin.000001 | 430585 | | | +------------------+----------+--------------+------------------+1 row in set (0.00 sec)

b. Set the values of File and Position that are displayed above to the slave (first server), along with the host, username and password: 

Page 12: PPPoE With Mikrotik and Radius

mysql> stop slave;mysql> CHANGE MASTER TO MASTER_HOST='192.168.25.102', MASTER_USER='repluser', MASTER_PASSWORD='replpassw', MASTER_LOG_FILE='mysql_bin.000001', MASTER_LOG_POS=430585;mysql> start slave;mysql> show slave status\G

The user 'repluser' has to be created in 192.168.25.102 and it should have replication permissions. However, since this user was created in 192.168.255.101 and a full backup of the database was done, this user should have been created when we restored the database to it.

In the output of the command show slave status\G , make sure that both Slave_IO_Running and Slave_SQL_Running are Yes , otherwise find out what is the problem.

4.3 Checking Replicated Databases

It can happen that the replicated databases become inconsistent (especially since we have used the option slave­skip­errors=all in /etc/my.cnf ). So, it is important to check and make sure that both databases have exactly the same data. This can be done using the mysql external tools in http://maatkit.sourceforge.net/ . They can be installed with: 

bash$ perl Makefile.PLbash# make install

Checking that the replicated databases are the same can be done with this command: 

bash$ mysql-table-checksum --replicate=replcheck.checksum --replcheck --user=root --askpass 192.168.25.121

The server that is given in the command should be the master, however, since we use a two­way replication, it doesn't matter which one we give. 

The database replcheck and the table checksum must be created in the database, before we run this command. The table checksum can be created like this: 

CREATE TABLE checksum ( db char(64) NOT NULL, tbl char(64) NOT NULL, chunk int NOT NULL, boundaries char(64) NOT NULL, this_crc char(40) NOT NULL, this_cnt int NOT NULL, master_crc char(40) NULL, master_cnt int NULL, ts timestamp NOT NULL, PRIMARY KEY (db, tbl, chunk) );

Page 13: PPPoE With Mikrotik and Radius

If it turns out that there are differences between the databases, an option for fixing them is the tool mysql­table­sync . 

5 SQL API for Radius Manager

In order to manage the radius, we used Radius Manager (http://www.dmasoftlab.com/), which is an application for managing the database of freeRadius, services, clients, etc. It even had some simple billing functionality. Unfortunately, Radius Manager was not free software (open source), although it was cheap and the support was quite responsive. We needed to integrate Radius Manager with our own client application (built with SugarCRM), so we tried hard to convince the RM guys to sell us the source code as well. However they would not listen at all about it. Anyway, we managed to do some kind of integration by modifying the database of Radius Manager from our client application. In order to do this, we built an external SQL API for Radius Manager.

Since Radius Manager is not free software, we are not going to describe here our experience about its installation and configuration. It does not need it and it does not deserve it. Instead, we are going to describe just the SQL API that we built to work around the integration problems.

5.1 Advantages of Using It

This SQL API helps to access the database of the Radius Manager from an outside program (from the program that manages the services and users). it is a library of MySQL procedures, which can be used to access and modify only those parts of the database that need to be touched. 

It has these advantages: 

● It encapsulates (hides) the complexity of the database from the outside programmer. The programmer doesn't have to know what tables or fields are there in the database, but just needs to know the procedures/functions that are available in the API, their parameters, return values, etc. 

● It makes simpler the code of the outside program, because instead of using complicated SQL queries, he just needs to call a procedure with the appropriate parameters. 

● The programmer is relived from the fear and the responsibility of touching something inappropriately in the database. The responsibility of doing things appropriately is taken over by the API. 

● In case that the structure of the radius manager is modified in the future releases, it is the responsibility of the API to take them into account, and the code of the external program doesn't need to change at all. 

5.2 Procedure Descriptions and Usage Examples

● user_get

procedure user_get(user varchar(32))

Page 14: PPPoE With Mikrotik and Radius

Returns the data of a given user. Gets the username of the user as a parameter (type: varchar(32)), and returns one or more records with the data of the users who match the data of the username. Matching is done with LIKE. It may return nothing if such a user does not exist. The record that is returned has these fields:     username, srvid, srvname, expiration, enabled, nr_conn

> call radius.user_get('%'); -- returns the list of all the users > call radius.user_get('%d%'); -- returns all the users with a 'd' in username > call radius.user_get('xyz'); -- returns nothing because such a user does not exist > call radius.user_get('test'); -- returns the data of the user 'test': +----------+-------+----------------+------------+---------+---------+ | username | srvid | srvname | expiration | enabled | nr_conn | +----------+-------+----------------+------------+---------+---------+ | test | 2 | 256/128 Biznes | 2007-12-30 | 1 | 1 | +----------+-------+----------------+------------+---------+---------+ 1 row in set (0.00 sec)

● user_add

procedure user_add(user varchar(32), passwd varchar(32), service_id int(11), nr_conn varchar(5), expxiration_date date )

Add a user in the database. It deletes first this user, in case that such a user already exists. It is the responsibility of the application to check and make sure that the users that are added are unique (no two users with the same username are added), otherwise the second user will overwrite the first one. 

> call radius.user_add('xyz', 'passwd', 3, 2, 2007-12-15); -- inserts a new user with 2 simultaneous connections > call radius.user_add('abc', 'passwd1', '4', '1', '2007-12-15'); -- inserts another user with only 1 connection > call radius.user_add('xyz', 'passwd', 3, 2, '2007-12-15'); -- gives error because the user 'xyz' already exists

● user_update

procedure user_update(user varchar(32), service_id int(11), nr_conn varchar(253), expiration_date date )

Update the data of the given user in the database. 

> call radius.user_update('xyz', 3, 2, '2008-1-30'); -- update the data of the user 'xyz' (for example expiration date is changed)

Page 15: PPPoE With Mikrotik and Radius

● user_set_password

procedure user_set_password(user varchar(32), passwd varchar(32) )

Set a new password to the given user. 

> call radius.user_set_password('xyz', 'passwd-1');

● user_change_service

procedure user_change_service(old_srvid varchar(100), new_srvid varchar(100))

Change an old service to a new one for all the users. This can be used in case that a service becomes obsolete and all the users of this service should be upgraded to another service. 

> call radius.user_change_service('3', '7');

● user_del

procedure user_del(user varchar(32))

Delete the given user. 

> call radius.user_del('xyz');

● service_get

procedure service_get(service_id varchar(100), service_name varchar(40) )

Return a list of services that match the given service id and name. Matching is done with LIKE, so the service name and id may contain wildcards and the procedure may return more than one record (or none if nothing matches). The result that is returned contains these fields: 

    srvid, srvname, download_rate, upload_rate, enabled

Fields download_rate and upload_rate are in Kbps, integers. The field enabled can be 1 or 0. If it is 0, then this service should not be used for the new clients and after some time may be deleted from the table. 

> call radius.service_get('%', '%'); -- returns a list of all the services > call radius.service_get('%', '%256%'); -- returns a list of the services that contain '256' in the name > call radius.service_get('%', '256');

Page 16: PPPoE With Mikrotik and Radius

-- returns nothing because no service has the name '256' > call radius.service_get('2', '%'); -- returns the service with id=2: +-------+----------------+---------------+-------------+---------+ | srvid | srvname | download_rate | upload_rate | enabled | +-------+----------------+---------------+-------------+---------+ | 2 | 256/128 Biznes | 256 | 128 | 1 | +-------+----------------+---------------+-------------+---------+ 1 row in set (0.00 sec)

● service_add

procedure service_add(service_name varchar(40), download_rate int(11), upload_rate int(11) )

Add a new service. Download and upload rates are in Kbps. In case that a service with the same id already exists, it is deleted first and then the new service is added. So, it is the responsibility of the application to make sure that it does not overwrite existing services. 

> call radius.service_add('256/128 Vetem 1 PC', 256, 128); > call radius.service_add('512/256 Vetem 1 PC', '512', '256');

● service_update

procedure service_update(service_id int(11), service_name varchar(40), download_rate int(11), upload_rate int(11), enabled int(11) )

Update the attributes of a service. 

+ call radius.service_update(2, '256/128 Biznes', 256, 128, 0); + call radius.service_update('3', '256/128 Familje', '256', '128', '0'); -- disable these services

● service_del

procedure service_del(service_id int(11))

Delete the service with the given id. It is deleted only if there are no users having this service. See also user_change_service(). 

+ call radius.service_del('2'); + call radius.service_del(3); -- delete these services

Page 17: PPPoE With Mikrotik and Radius

5.3 Implementation

The MySQL procedures can be declared in a file, for example rm_api.sql and then they can be loaded in the MySQL server like this: 

bash$ mysql -p -u rootmysql> ?mysql \. rm_api.sql

or like this: 

bash$ mysql -p -u root < rm_api.sql

The declaration of the procedures is like this: 

/** * Set the delimiter of the SQL commands to double semicolon, * because semicolon needs to be used inside the procedure declaration * to separate the statements. */DELIMITER ;;

/** * Select the database that will be used by the procedures and functions. * The procedures and functions will be attached to this database. */USE radius ;;

/** procedure user_get * Returns the data of a given user. * Gets the username of the user as a parameter (type: varchar(32)), * and returns one or more records with the data of the users who * match the data of the username. Matching is done with LIKE. * It may return nothing if such a user does not exist. * The record that is returned has these fields: * username, srvid, srvname, expiration, enabled, nr_conn */DROP PROCEDURE IF EXISTS user_get ;;CREATE PROCEDURE user_get(user varchar(32))BEGIN SELECT rm_users.username, rm_services.srvid, srvname, expiration, enableuser AS enabled, radcheck.Value AS nr_conn FROM rm_users LEFT JOIN rm_services USING (srvid) LEFT JOIN radcheck ON ( rm_users.username = radcheck.UserName AND radcheck.Attribute = 'Simultaneous-Use' ) WHERE rm_users.username LIKE user;END;;

/** procedure user_add * Add a user in the database. * Takes these parameters: * username, password, service_id, nr_conn, expiration_date */DROP PROCEDURE IF EXISTS user_add ;;CREATE PROCEDURE user_add(user varchar(32), passwd varchar(32), service_id int(11), nr_conn varchar(5),

Page 18: PPPoE With Mikrotik and Radius

expiration_date date)BEGIN ### first delete it, in case that such a user exists CALL user_del(user);

### insert a record into the table rm_users INSERT INTO rm_users SET username = user, password = MD5(passwd), srvid = service_id, expiration = expiration_date, enableuser = '1', createdon = NOW(), createdby = 'admin';

### insert two records into the table radcheck INSERT INTO radcheck (UserName, Attribute, op, Value) VALUES (user, 'Simultaneous-Use', ':=', nr_conn), (user, 'User-Password', ':=', passwd);END;;

/** procedure user_update * Update the data of the given user in the database. * Takes these parameters: * username, service_id, nr_conn, expiration_date */DROP PROCEDURE IF EXISTS user_update ;;CREATE PROCEDURE user_update(user varchar(32), service_id int(11), nr_conn varchar(253), expiration_date date)BEGIN UPDATE rm_users SET srvid = service_id, expiration = expiration_date, enableuser = '1', createdon = NOW(), createdby = 'admin' WHERE username = user;

UPDATE radcheck SET Value = nr_conn WHERE UserName = user AND Attribute = 'Simultaneous-Use';END;;

/** procedure user_set_password * Set a new password to the given user. * Gets the parameters: user, passwd */DROP PROCEDURE IF EXISTS user_set_password ;;CREATE PROCEDURE user_set_password(user varchar(32), passwd varchar(32))BEGIN UPDATE rm_users SET password = MD5(passwd) WHERE username = user;END;;

Page 19: PPPoE With Mikrotik and Radius

/** procedure user_change_service * Change an old service to a new one for all the users. * Gets the parameters: old_srvid, new_srvid */DROP PROCEDURE IF EXISTS user_change_service ;;CREATE PROCEDURE user_change_service(old_srvid varchar(100), new_srvid varchar(100))BEGIN UPDATE rm_users SET srvid = new_srvid WHERE srvid = old_srvid;END;;

/** procedure user_del * Delete the given user. */DROP PROCEDURE IF EXISTS user_del ;;CREATE PROCEDURE user_del(user varchar(32))BEGIN DELETE FROM rm_users WHERE username = user; DELETE FROM radcheck WHERE UserName = user;END;;

/** procedure service_get * Return a list of services that match the given service id and name. * Matching is done with LIKE, so the service name and id may contain * wildcards and the procedure may return more than one records * (or none if nothing matches). * The result that is returned contains these fields: * srvid, srvname, download_rate, upload_rate, enabled * 'download_rate' and 'upload_rate' are in Kbps, integers * 'enabled' can be 1 or 0. If it is 0, then this service * should not be used for the new clients and after some * time may be deleted from the table. */DROP PROCEDURE IF EXISTS service_get ;;CREATE PROCEDURE service_get(service_id varchar(100), service_name varchar(40) )BEGIN SELECT srvid, srvname, (downrate DIV 1024) AS download_rate, (uprate DIV 1024) AS upload_rate, enableservice AS enabled FROM rm_services WHERE srvid LIKE service_id AND srvname LIKE service_name;END;;

/** procedure service_add * Add a new service. Parameters that are given to this procedure * are these: service_name, download_rate, upload_rate * Download and upload rates are integers in Kbps. */DROP PROCEDURE IF EXISTS service_add ;;CREATE PROCEDURE service_add(service_id varchar(100), service_name varchar(40), download_rate int(11), upload_rate int(11))BEGIN ### if such a service exists, delete it first CALL service_del(service_id);

Page 20: PPPoE With Mikrotik and Radius

### insert the new service INSERT INTO rm_services SET srvid = service_id, srvname = service_name, downrate = (download_rate * 1024), uprate = (upload_rate * 1024), enableservice = '1', limitexpiration = '1', poolname = 'pool0';END;;

/** procedure service_update * Update the attributes of a service. * The parameters of the procedure are: * service_id, service_name, download_rate, upload_rate, enabled * Download and upload rates are integers in Kbps. */DROP PROCEDURE IF EXISTS service_update ;;CREATE PROCEDURE service_update(service_id int(11), service_name varchar(40), download_rate int(11), upload_rate int(11), enabled int(11))BEGIN UPDATE rm_services SET srvname = service_name, downrate = (download_rate * 1024), uprate = (upload_rate * 1024), enableservice = enabled WHERE srvid = service_id;END;;

/** procedure service_del * Delete the service with the given id. * It is deleted only if there are no users having this service. */DROP PROCEDURE IF EXISTS service_del ;;CREATE PROCEDURE service_del(service_id int(11))BEGIN ### get the number of the users which have this service DECLARE cnt INT DEFAULT 0; SELECT COUNT(*) INTO cnt FROM rm_users WHERE srvid = service_id;

### delete the service only if there are no users having it IF cnt = 0 THEN DELETE FROM rm_services WHERE srvid = service_id; END IF;END;;

/** Set the delimiter of the SQL commands back to semicolon. */DELIMITER ;

5.4 User Access Rights

Access rights can be arranged to the user used by the program in such a way that it is able to execute only these procedures. It can be done as follows: 

Page 21: PPPoE With Mikrotik and Radius

/** * Create a user and assign privileges to be able to execute * the functions and procedures in this file. */USE radius;DROP USER 'prog'@'192.168.25.%';CREATE USER 'prog'@'192.168.25.%' IDENTIFIED BY 'progpassw';GRANT EXECUTE ON PROCEDURE user_get TO 'prog'@'192.168.25.%';GRANT EXECUTE ON PROCEDURE user_add TO 'prog'@'192.168.25.%';GRANT EXECUTE ON PROCEDURE user_update TO 'prog'@'192.168.25.%';GRANT EXECUTE ON PROCEDURE user_set_password TO 'prog'@'192.168.25.%';GRANT EXECUTE ON PROCEDURE user_change_service TO 'prog'@'192.168.25.%';GRANT EXECUTE ON PROCEDURE user_del TO 'prog'@'192.168.25.%';GRANT EXECUTE ON PROCEDURE service_get TO 'prog'@'192.168.25.%';GRANT EXECUTE ON PROCEDURE service_add TO 'prog'@'192.168.25.%';GRANT EXECUTE ON PROCEDURE service_update TO 'prog'@'192.168.25.%';GRANT EXECUTE ON PROCEDURE service_del TO 'prog'@'192.168.25.%';

/** * Create a user for phpMyAdmin, which can see only certain tables. */USE radius;DROP USER 'prog'@'localhost';CREATE USER 'prog'@'localhost' IDENTIFIED BY 'progpassw';GRANT SELECT ON rm_users TO 'prog'@'localhost';GRANT SELECT ON rm_services TO 'prog'@'localhost';GRANT SELECT ON radcheck TO 'prog'@'localhost';

In order to check what is happening in the database with phpMyAdmin, another local user has been created, which has only SELECT access.

5.5 Using It On SugarCRM

SugarCRM has some logic hooks where you can call custom code. These logic hooks are placed before saving a record, before deleting it etc. In these logic hooks we have placed our code which integrates SugarCRM with the database of freeRadius. So, the clients are managed on SugarCRM, however some relevant data (like username, password, etc.) are replicated on the freeRadius database as well.

The custom code that does it, looks like this:

SugarCRM/custom/modules/Accounts/UpdateRadiusClients.php:

<?php /** * This file contains hooks of the module Account. */

require_once('data/SugarBean.php');require_once('modules/Accounts/Account.php');require_once('custom/include/MysqlDB.php');

r

/** * The class UpdateRadiusClients contains some hooks * for the module Accounts, which keep updated the data * of the clients in the radius manager. */class UpdateRadiusClients{

Page 22: PPPoE With Mikrotik and Radius

/** connection to the radius database */ var $radb;

var $default_email = '[email protected]';

function __construct() { $this->radb = new MysqlDB('192.168.25.101', 'usr', 'pass', 'radius'); }

function debug($msg) { $GLOBALS['log']->fatal($msg); }

/** Fired before a record is deleted. */ function before_delete(&$bean, $event, $arguments) { //delete the user from the radius manager as well $username = $bean->username_c; try { $this->radb->query("call user_del('$username');"); } catch (Exception $e) { $msg = 'UpdateRadiusClients::before_delete(): ' . $e->getMessage(); $GLOBALS['log']->fatal($msg); print $e->getMessage(); exit(1); } }

/** Fired before a record is saved. */ function before_save(&$bean, $event, $arguments) { try { //get the old (unmodified yet) values of the data $old_bean = new Account(); $old_bean->retrieve($bean->id);

//check whether this is a new record or an existing one if ($old_bean->id=='') { //this is a new record, add a new user $this->add_radius_user($bean); } else { //update the user data in radius manager $this->update_radius_user($bean, $old_bean); } } catch (Exception $e) { $msg = 'UpdateRadiusClients::before_save(): ' . $e->getMessage(); $GLOBALS['log']->fatal($msg); print $e->getMessage(); exit(1); } }

/** add/insert a new user in the database of radius manager */ function add_radius_user(&$bean)

Page 23: PPPoE With Mikrotik and Radius

{ //get variables that will be stored in radius $username = $bean->username_c; $password = $bean->password_c; $service = $bean->service_c; $nr_conn = $bean->simultaneous_connections_c; $mac = $bean->mac_address_c; $expiration_date = $bean->expiration_date_c; $fullname = $bean->name; if ($fullname=='') $fullname = $username;

//$email = $bean->email1; $email = $_REQUEST[$_REQUEST['emailAddressPrimaryFlag']]; if ($email=='') $email = $this->default_email;

//make sure that the username is not already in use if ($this->username_exists_in_sugar($username)) { $msg = "<strong>The username '$username' is already used " . "for another client.<br/>\n" . "Please try again with another username.</strong>"; print $msg; exit(1); } if ($this->username_exists_in_radius($username)) { $msg = "<strong>The username '$username' is already used in RADIUS" . "for another client.<br/>\n" . "Please try again with another username.</strong>"; print $msg; exit(1); }

//build the field comment of radius manager $comment = $bean->shipping_address_street . ' -- ' . $bean->description; //add a new user in radius $query = ("call user_add('$username', '$password', '$service', '$nr_conn'," . " '$expiration_date', '$mac', '$fullname', " . "'$email', '$comment');"); $this->radb->query($query); } /** update user in the database of radius manager */ function update_radius_user(&$bean, &$old_bean) { //get the fields of the client $username = $bean->username_c; $password = $bean->password_c; $service = $bean->service_c; $nr_conn = $bean->simultaneous_connections_c; $mac = $bean->mac_address_c; $expiration_date = $bean->expiration_date_c; $fullname = $bean->name; if ($fullname=='') $fullname = $username;

//$email = $bean->email1; $email = $_REQUEST[$_REQUEST['emailAddressPrimaryFlag']]; if ($email=='') $email = $this->default_email;

//if the old username does not exist in radius, then create it $old_username = $old_bean->username_c; if (!$this->username_exists_in_radius($old_username)) { $query = "call user_add('$username','$password','$service','$nr_conn'," . " '$expiration_date','$mac','$fullname','$email');";

Page 24: PPPoE With Mikrotik and Radius

$this->radb->query($query); }

//update the username if it is changed if ($username != $old_username) { //make sure that the new username is not already in use if ( $this->username_exists_in_sugar($username) or $this->username_exists_in_radius($username) ) { //use the old username $username = $old_username; $bean->username_c = $old_username;

//todo: display a notification message about this problem } else { //change the username $query = "call user_change_username('$old_username', '$username')"; $this->radb->query($query); } }

//update the password if it is changed $old_password = $old_bean->password_c; $password = $bean->password_c; if ($password != $old_password) { $query = "call user_set_password('$username', '$password')"; $this->radb->query($query); }

//build the field comment of radius manager $comment = $bean->shipping_address_street . ' -- ' . $bean->description;

//update the rest of the fields $query = ( "call user_update('$username', '$service', '$nr_conn', " . "'$expiration_date', '$mac', '$fullname', " . "'$email', '$comment');" ); $this->radb->query($query); }

/** * Return true if the given username already exists * in the sugar database. Otherwise return false. */ function username_exists_in_sugar($username) { //check in the sugar database $client = new Account(); $client->retrieve_by_string_fields(array('username_c'=>$username)); if ($client->username_c == $username) return true;

//not found return false; }

/** * Return true if the given username already exists * in the radius database. Otherwise return false. */ function username_exists_in_radius($username) {

Page 25: PPPoE With Mikrotik and Radius

//check in the radius database $query = "select user_check('$username') as username"; $result = $this->radb->query($query); $record = $result->fetch_object(); if ($record->username == $username) return true;

//not found return false; }}?>

SugarCRM/custom/include/MysqlDB.php:

<?php /** * This class handles the queries to a mysql database. */class MysqlDB{ var $conn = false; //connection to the database

/** constructor */ function __construct($db_host, $db_user, $db_pass, $db_name) { //create a new connection to the database $this->conn = new mysqli($db_host, $db_user, $db_pass, $db_name);

//check for errors if (!$this->conn) { $errno = mysqli_connect_errno(); $error = mysqli_connect_error(); throw new Exception("Can't connect to DB: $errno : $error"); } }

function __destruct() { $this->conn->close(); }

/** run a mysql query and return the result */ function query($query) { //if there is no db connection, cannot run the query if (!$this->conn) return;

//debug //$GLOBALS['log']->fatal('MysqlDB::query(): '.$query);

//run the query and get the result $result = $this->conn->query($query); //check for errors if (!$result) { $errno = mysqli_errno($this->conn); $error = mysqli_error($this->conn); throw new Exception("Query failed: $errno : $error : $query\n"); }

Page 26: PPPoE With Mikrotik and Radius

//return the result return $result; }}?>

6 Almost Automated Configuration of MikroTik

After a MikroTik server has been installed, it can be configured quickly by doing copy/paste of the configuration commands. This can be done easily if we login to MikroTik using a linux terminal. 

Note: In order to login to MikroTik through a linux terminal, the network configuration has to be done manually first, right after the installation. It can be done by adding an IP address. A gateway may be needed as well.

We assume here that the MikroTik servers are named: MikroTik1, MikroTik2, etc. Initially we have some configuration files in cfg/ , named  MikroTik1.cfg, MikroTik2.cfg, etc. After running the script generate-mt-setup.sh, the files  MikroTik1.mt, MikroTik2.mt, etc. will be generated in  setup/.

6.1 generate­mt­setup.sh

The script generate-mt-setup.sh is used to (re)generate the setup configuration scripts for all the MikroTik servers: 

#!/bin/bash### generate the setup configuration scripts for all the MikroTik servers

./mikromik-setup.sh cfg/MikroTik1.cfg > setup/MikroTik1.mt

./mikrotik-setup.sh cfg/MikroTik2.cfg > setup/MikroTik2.mt

./mikrotik-setup.sh cfg/MikroTik3.cfg > setup/MikroTik3.mt

./mikrotik-setup.sh cfg/MikroTik4.cfg > setup/MikroTik4.mt

./mikrotik-setup.sh cfg/MikroTik5.cfg > setup/MikroTik5.mt

6.2 mikrotik­setup.sh

The script mikrotik-setup.sh is used to generate and output the MikroTik commands that are used to configure a MikroTik server with PPPoE service. The commands that are generated can be executed on the MikroTik server with copy/paste (all of them or many of them at once). The script should get an argument, which is the name of a file which contains configuration parameters that are specific for each server (for example IP, gateway, etc.). 

#!/bin/bash### This shell script generates and output the commands that are used### to configure a MikroTik server with PPPoE service.### The commands that are generated can be executed on the MikroTik server### with copy/paste (all of them at once).

### get the configuration file as the first parametercfgfile=${1:-MikroTik.cfg}

Page 27: PPPoE With Mikrotik and Radius

### include the configuration file. $cfgfile

### generate and output the MikroTik commandscat <<EOF### add an address on the outside (WAN) interface of the MikroTik# / ip address add address=$ADDRESS interface=$WAN_IF

### add a gateway# / ip route add gateway=$GATEWAY

### set a password# / password# # mt-$ID# mt-$ID

## change the name of the server/ system identity set name=MikroTik$ID

### set the DNS servers/ ip dns set primary-dns=$DNS1 secondary-dns=$DNS2

### setup NAT on the outside interface of the MikroTik/ ip firewall nat add chain=srcnat out-interface=$WAN_IF action=masquerade

### create a PPPoE service on the inner (LAN) interface of the MikroTik/ ppp profile add name=pppoe_profile local-address=10.0.0.0/ interface pppoe-server server add service-name=pppoe_service \\ default-profile=pppoe_profile interface=$PPPOE_IF \\ authentication=pap,chap max-sessions=450 \\ one-session-per-host=no disabled=no

### add another address for connecting to the radius server/ ip address add address=192.168.25.$ID/24 interface=$RADIUS_IF

### disable masquerading for the radius LAN (192.168.25.0/24)/ ip firewall nat add chain=srcnat out-interface=$WAN_IF \\ src-address=192.168.25.0/24 action=return/ ip firewall nat move 1 0

### add radius servers for any PPP service on MikroTik/ radius add service=ppp address=192.168.25.101 secret=passw \\ timeout=2000ms called-id=pppoe_service/ radius add service=ppp address=192.168.25.102 secret=passw \\ timeout=2000ms called-id=pppoe_service

### tell MikroTik to use the radius servers for authentication and accounting / ppp aaa set use-radius=yes/ ppp aaa set accounting=yes/ ppp aaa set interim-update=60/ radius incoming set accept=yes

### add some pools of about 500 IPs each/ ip pool add name=pool0 ranges=10.0.0.0/23/ ip pool add name=pool1 ranges=10.0.2.0/23/ ip pool add name=pool2 ranges=10.0.4.0/23/ ip pool add name=pool3 ranges=10.0.6.0/23/ ip pool add name=pool4 ranges=10.0.8.0/23/ ip pool add name=pool5 ranges=10.0.10.0/23/ ip pool add name=pool6 ranges=10.0.12.0/23/ ip pool add name=pool7 ranges=10.0.14.0/23/ ip pool add name=pool8 ranges=10.0.16.0/23/ ip pool add name=pool9 ranges=10.0.18.0/23

Page 28: PPPoE With Mikrotik and Radius

### logout/ quit

EOF

6.3 cfg/MikroTik1.cfg

The file cfg/MikroTik1.cfg contains some configuration variables for the values that are different for each MikroTik that is configured. 

### These configuration variables are included by the script### that generates the MikroTik setup commands. Their values### should be set according to the server where MikroTik is### installed. The ID should be a different number from the### other MikroTiks that connect to the same server radius.

ID=1

WAN_IF=ether1ADDRESS=192.168.25.21/24GATEWAY=192.168.25.1DNS1=192.168.25.11DNS2=4.2.2.2

PPPOE_IF=ether2RADIUS_IF=ether2

6.4 setup/MikroTik1.mt

These are the configuration commands that are generated for a MikroTik server by the script mikrotik-setup.sh , which takes as input the configuration variables in the file cfg/MikroTik1.cfg . These commands can be copy/pasted to the MikroTik prompt from a terminal. The commands that are commented should be given manually right after the installation of the MikroTik. 

### add an address on the outside (WAN) interface of the MikroTik# / ip address add address=192.168.25.21/24 interface=ether1

### add a gateway# / ip route add gateway=192.168.25.1

### set a password# / password# # mt-1# mt-1

## change the name of the server/ system identity set name=MikroTik1

### set the DNS servers/ ip dns set primary-dns=192.168.25.11 secondary-dns=4.2.2.2

### setup NAT on the outside interface of the MikroTik/ ip firewall nat add chain=srcnat out-interface=ether1 action=masquerade

Page 29: PPPoE With Mikrotik and Radius

### create a PPPoE service on the inner (LAN) interface of the MikroTik/ ppp profile add name=pppoe_profile local-address=10.0.0.0/ interface pppoe-server server add service-name=pppoe_service \ default-profile=pppoe_profile interface=ether2 \ authentication=pap,chap max-sessions=450 \ one-session-per-host=no disabled=no

### add another address for connecting to the radius server/ ip address add address=192.168.25.1/24 interface=ether2

### disable masquerading for the radius LAN (192.168.25.0/24)/ ip firewall nat add chain=srcnat out-interface=ether1 \ src-address=192.168.25.0/24 action=return/ ip firewall nat move 1 0

### add radius servers for any PPP service on MikroTik/ radius add service=ppp address=192.168.25.101 secret=radiuspassw \ timeout=2000ms called-id=pppoe_service/ radius add service=ppp address=192.168.25.102 secret=radiuspassw \ timeout=2000ms called-id=pppoe_service

### tell MikroTik to use the radius servers for authentication and accounting / ppp aaa set use-radius=yes/ ppp aaa set accounting=yes/ ppp aaa set interim-update=60/ radius incoming set accept=yes

### add some pools of about 500 IPs each/ ip pool add name=pool0 ranges=10.0.0.0/23/ ip pool add name=pool1 ranges=10.0.2.0/23/ ip pool add name=pool2 ranges=10.0.4.0/23/ ip pool add name=pool3 ranges=10.0.6.0/23/ ip pool add name=pool4 ranges=10.0.8.0/23/ ip pool add name=pool5 ranges=10.0.10.0/23/ ip pool add name=pool6 ranges=10.0.12.0/23/ ip pool add name=pool7 ranges=10.0.14.0/23/ ip pool add name=pool8 ranges=10.0.16.0/23/ ip pool add name=pool9 ranges=10.0.18.0/23

### logout/ quit

7 Optimize and Test the Performance

We need to know (or estimate) how much load can keep the server, how many clients it can serve without creating problems. For this reason, we simulate a high load by sending too many requests to the server, in order to see up to what point the server can bear the load. 

However, before testing the server we should optimize it so that it can have the best performance with the resources that are available (RAM etc.). 

7.1 Optimize RAM

The usage of RAM by the server can be seen at the statistics generated by MRTG. It can be seen also using linux commands such as top , free, ps and pstree. 

● The command top shows the most active processes. The command pstree displays a graphical tree of processes and their children. 

Page 30: PPPoE With Mikrotik and Radius

● Using the command ps I can find out the processes that consume the most amount of RAM and how much uses each of them. I do it like this:  

bash# ps -e -o vsize,comm | sort -k1 -n -r | head -n 20146896 mysqld123064 radiusd 36412 httpd 36392 httpd 36380 httpd 36380 httpd 36376 httpd 36128 httpd 36128 httpd 36120 httpd 30200 httpd 29600 sort 13072 dbus-daemon 12800 pcscd 11040 snmpd 10720 restorecond 9156 sendmail 8252 sshd 8252 sshd 7996 sendmail

● The command free shows the usage of memory, how much is free etc: 

bash# free total used free shared buffers cachedMem: 1026844 449416 577428 0 141572 178628-/+ buffers/cache: 129216 897628Swap: 1052248 0 1052248

From the graph of the free memory we can notice that gradually the server uses all of the free RAM that is available. Initially I thought that maybe there is some problem with memory leaking from some program (e.g. mysqld). However, after googling for this problem, I found out that this is something normal for a linux server: 

  The kernel will attempt to use any available memory for buffering and  cacheing, as this makes things run faster. When applications need more  memory, buffer and cache space is released. So the figure you need to  look at in the "free" output is the one in the row marked "­/+  buffers/cache:", which shows memory usage not in buffers and cache; that  represents how much memory you're "really" using.

See also these discussions: http://linux.derkeiler.com/Mailing­Lists/Fedora/2005­02/3149.html and http://linux.derkeiler.com/Newsgroups/linux.redhat.misc/2004­01/0220.html .

● In order to optimize the usage of RAM, stop any services that use a lot of memory and are not necessary. I stopped ConsoleKit and yum­updatesd like this: 

service ConsoleKit stopservice ConsoleKit statuschkconfig ConsoleKit offchkconfig --list ConsoleKit

service yum-updatesd stopservice yum-updatesd status

Page 31: PPPoE With Mikrotik and Radius

chkconfig yum-updatesd offchkconfig --list yum-updatesd

7.2 Optimize MySQL

In order to check the performance of the mysql server and to discover any problems, we can use the tools mysqlreport and mysqlsla , as described in this guide: Non­technical Guide to Isolating Slow MySQL Queries . 

● First download mysqlreport and mysqlsla from http://hackmysql.com/ and place them at /usr/local/bin/ . 

● Then create the cron job /etc/cron.daily/mysqlreport.sh (which will send a daily report by email): 

#!/bin/bash### send a report to root by email, about the performance of the mysql server/usr/local/bin/mysqlreport --all --flush-status \ --user root --password sqladmin --email root

Alternatively, this command can be executed periodically from the command line: 

mysqlreport --all --user root --password

● Add these lines in /etc/my.cnf , in order to log the slow queries: 

### log slow querieslog-slow-querieslong_query_time=1

Then restart mysql: service mysql restart .

● Finally, wait for the report (which should come daily) and check the values of Read ratio , Slow , Waited , etc. (as described in http://hackmysql.com/nontech ). If there are slow queries, find out which are these queries, using a command like this: 

mysqlsla --slow /var/lib/mysql/slow_queries.log > top_10_slow_queries

In order to optimize mysql we can do these things: 

● Modify the file /etc/my.cnf similarly to the following lines and then restart mysqld: 

[mysqld]. . . . .### options for increasing performanceskip-name-resolvemax_connections=500

Page 32: PPPoE With Mikrotik and Radius

key_buffer=128Mtable_cache=256read_buffer_size=1Mread_rnd_buffer_size=4Mmyisam_sort_buffer_size=64Mthread_cache_size=8query_cache_size=16Mthread_concurrency=2. . . . .

[mysqldump]quickmax_allowed_packet = 16M

[isamchk]key_buffer = 128Msort_buffer_size = 128Mread_buffer = 2Mwrite_buffer = 2M

[myisamchk]key_buffer = 128Msort_buffer_size = 128Mread_buffer = 2Mwrite_buffer = 2M

These values are mainly copied from the file /usr/share/mysql/my-large.cnf . See also the articles in http://www.databasejournal.com/features/mysql/article.php/3367871 and http://www.debianhelp.co.uk/mysqlperformance.htm . 

● As advised in /usr/local/share/doc/freeradius/tuning_guide , we convert to the engine innodb the table radacct : 

mysql> ALTER TABLE radacct ENGINE=INNODB;

● Then, to increase the performance of the innodb engine, we also add these parameters at /etc/my.cnf : 

### innodb options for incleasing performanceinnodb-buffer_pool_size=256Minnodb_additional_mem_pool_size=20Minnodb_log_file_size=64Minnodb_log_buffer_size=8M

● We create a multi column index for the (UserName,AcctStopTime) attributes, as advised in /usr/local/share/doc/freeradius/tuning_guide : 

mysql> EXPLAIN SELECT UserName, AcctStopTime FROM radacct;mysql> ALTER TABLE radacct ADD INDEX username_acctsstoptime --> (UserName, AcctStopTime);mysql> EXPLAIN SELECT UserName, AcctStopTime FROM radacct;

Read also this article: http://www.databasejournal.com/features/mysql/article.php/10897_1382791_1

Page 33: PPPoE With Mikrotik and Radius

7.3 Optimize FreeRADIUS

The optimization of FreeRADIUS is based on the suggestions given in the file 

/usr/local/share/doc/freeradius/tuning_guide . 

● First of all we add the noatime attribute to the log files: 

chattr -R -A /usr/local/var/log/radius/lsattr /usr/local/var/log/radius/

This will decrease the number of accesses to the disk because access time of the log files will not be recorded. 

● Disable at all detailed logs in the configuration file /usr/local/etc/raddb/radiusd.conf by commenting them out (they can be found by searching for the word detail ): 

# Log authentication requests to the log file.## allowed values: {no, yes}##log_auth = yeslog_auth = no

# Write a detailed log of all accounting records received. ## 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# }

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

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

# detail post_proxy_log {# detailfile = ${radacctdir}/%{Client-IP-Address}/post-proxy-detail-%Y%m%# detailperm = 0600# }

authorize { # If you want to have a log of authentication requests, # un-comment the following line, and the 'detail auth_log' # section, above.

Page 34: PPPoE With Mikrotik and Radius

# auth_log}

accounting { # # Create a 'detail'ed log of the packets. # Note that accounting requests which are proxied # are also logged in the detail file.# detail# daily}

post-auth { # # If you want to have a log of authentication replies, # un-comment the following line, and the 'detail reply_log' # section, above.# reply_log}

pre-proxy { # If you want to have a log of packets proxied to a home # server, un-comment the following line, and the # 'detail pre_proxy_log' section, above.# pre_proxy_log}

post-proxy {

# If you want to have a log of replies from a home server, # un-comment the following line, and the 'detail post_proxy_log' # section, above.# post_proxy_log}

● We can also comment the lines related to unix , radwtmp and radutmp in radiusd.conf . 

● Increase the value of cleanup_delay and max_requests : 

# cleanup_delay: The time to wait (in seconds) before cleaning up# a reply which was sent to the NAS.## The RADIUS request is normally cached internally for a short period# of time, after the reply is sent to the NAS. The reply packet may be# lost in the network, and the NAS will not see it. The NAS will then# re-send the request, and the server will respond quickly with the# cached reply.## If this value is set too low, then duplicate requests from the NAS# MAY NOT be detected, and will instead be handled as seperate requests.## If this value is set too high, then the server will cache too many# requests, and some new requests may get blocked. (See 'max_requests'.)## Useful range of values: 2 to 10##cleanup_delay = 5cleanup_delay = 10

# max_requests: The maximum number of requests which the server keeps# track of. This should be 256 multiplied by the number of clients.# e.g. With 4 clients, this number should be 1024.

Page 35: PPPoE With Mikrotik and Radius

## If this number is too low, then when the server becomes busy,# it will not respond to any new requests, until the 'cleanup_delay'# time has passed, and it has removed the old requests.## If this number is set too high, then the server will use a bit more# memory for no real benefit.## If you aren't sure what it should be set to, it's better to set it# too high than too low. Setting it to 1000 per client is probably# the highest it should be.## Useful range of values: 256 to infinity##max_requests = 1024max_requests = 15000000

● Turn off proxy requests: 

#proxy_requests = yes#$INCLUDE ${confdir}/proxy.confproxy_requests = no

● Increase some values at thread pool : 

thread pool { #max_servers = 32 max_servers = 128 #min_spare_servers = 3 #max_spare_servers = 10 min_spare_servers = 5 max_spare_servers = 16}

● Modify /usr/local/etc/raddb/sql.conf and increase the number of sql connections. It should be greater than the number of the radius servers: 

# number of sql connections to make to server #num_sql_socks = 5 ### this value is greater than max_servers (=128)

num_sql_socks = 130 # number of seconds to dely retrying on a failed database # connection (per_socket) #connect_failure_retry_delay = 60 connect_failure_retry_delay = 10

● Finally restart radiusd : /usr/local/sbin/rc.radiusd restart

Page 36: PPPoE With Mikrotik and Radius

7.4 Testing the Performance

When a client tries to connect to internet, MikroTik makes an authentication/authorization request to the radius server. Then, after the client is connected, MikroTik sends periodically an accounting update to the radius server, telling how much download/upload traffic the client has done during this interval. We have set this interval to one minute in MikroTik. So, each minute, the radius server gets an accounting request for each connected client, and it writes the data to the MySQL database.

To simulate a client, we use the script radius­client.sh . It keeps running and sending update requests to the radius server until the stop time, then it terminates. The interval between the update requests is 5sec, so, the load on the server that is generated by this client will be approximately equal to the load of 10 real clients. 

Then we use the scrip test­radius.sh which runs many of such clients in parallel, in order to increase the load. The number of the clients that is generated is configurable. The script stop­test.sh can be used to interrupt the simulation at any time. 

From the tests that we did, we found out that in general the bottleneck of the system is the MySQL database. One way to increase its performance is to build a MySQL cluster, with two or more MySQL servers. However this requires additional resources (additional servers with big amounts of RAM). At that time we could still handle out clients without a MySQL cluster, so we didn't try to build it.

● radius­client.sh

#!/bin/bash ### Simulate a radius client. ### It will keep running and sending requests to the radius server ### until the stop time, then it will terminate.

### go to this directory cd $(dirname $0)

### get the parameters if [ "$2" = "" ] then echo "Usage: $0 client_id stop_time" exit fi id=$1 stop_time=$2

### convert the stop time into seconds stop_time_sec=$(date --date="$stop_time" +%s)

### variables radius_server="192.168.25.101" secret="test" user="testing-radius" passw="test" interval=5 #radclient="/usr/local/bin/radclient -x" radclient="/usr/local/bin/radclient"

### simple packages for authentication and accounting auth_pkg="User-Name=$user,User-Password=$passw" acct_pkg_start="User-Name=$user,Acct-Session-Id=$id,Acct-Status-Type=Start" acct_pkg_stop="User-Name=$user,Acct-Session-Id=$id,Acct-Status-Type=Stop"

Page 37: PPPoE With Mikrotik and Radius

acct_pkg_update=" User-Name=$user, Acct-Session-Id=$id, Acct-Status-Type=Interim-Update, Service-Type=Framed-User, Framed-Protocol=PPP, User-Name=$user , Calling-Station-Id=00:11:43:9f:90:53, Called-Station-Id=Test, NAS-Port-Id=ether2, Framed-IP-Address="10.2.255.255", Acct-Authentic=RADIUS, Acct-Session-Time=5461, Acct-Input-Octets=974290, Acct-Input-Gigawords=0, Acct-Input-Packets=6458, Acct-Output-Octets=3578820, Acct-Output-Gigawords=0, Acct-Output-Packets=6338, NAS-Identifier=TEST, Acct-Delay-Time=0, Client-IP-Address=192.168.25.22"

### start the connection #echo $acct_pkg_stop | $radclient $radius_server acct $secret echo $auth_pkg | $radclient $radius_server auth $secret echo $acct_pkg_start | $radclient $radius_server acct $secret

### send update account packages periodically until stop time curr_time_sec=$(date +%s) #echo $curr_time_sec ## debug while [ $curr_time_sec -lt $stop_time_sec ] do echo $acct_pkg_update | $radclient $radius_server acct $secret sleep $interval curr_time_sec=$(date +%s) #echo $curr_time_sec ## debug done

### stop the connection echo $acct_pkg_stop | $radclient $radius_server acct $secret

● test­radius.sh

#!/bin/bash ### test the resources of the radius server by starting ### many clients and sending a lot of request packages to it

### go to this directory cd $(dirname $0)

### get the parameters of the script if [ "$2" = "" ] then echo "Usage: $0 nr_clients stop_time" exit fi nr_clients=$1 stop_time=$2

for (( i=0 ; i < $nr_clients ; i++ )) do id=$(expr $i + 1) echo ./radius-client.sh $id $stop_time

Page 38: PPPoE With Mikrotik and Radius

./radius-client.sh $id $stop_time & sleep 1 done

● stop­test.sh

#!/bin/bash ### stop the test by killing the processes

pslist=$(ps ax | grep radius-client.sh | gawk '{print $1}') for ps in $pslist do kill -9 $ps done

8 Making Backups

Backups are stored in the directory /backup/ on the radius server. Some of them are generated periodically by cron jobs, some of them manually. They can be downloaded from http://192.168.25.101/backup/ in order to write them in a CD or DVD. They are made accessible via http by the configuration file /etc/httpd/conf.d/backup.conf, which has this content: 

Alias /backup /backup<Directory "/backup"> Options +Indexes order deny,allow deny from all allow from 127.0.0.1 allow from 192.168.25.0/24</Directory>

8.1 MikroTik

Binary backups of the MikroTik servers can be done by the script /backup/mikrotik/backup.sh . It takes automatically backups from the MikroTik servers. In case that a MikroTik server needs to be reinstalled for some reason, its configuration can be restored easily from the backup. First the backup is uploaded by FTP on the MikroTik server, then it is restored using the command " / system backup save name=filename.backup " . 

#!/bin/bash### Get binary backups of all the MikroTik servers.### This script can be executed manually or periodicly (by a cron job).### However, since the configuration of the MikroTik servers is standard### and does not change over the time (because all the data of the clients### are stored in radius), there is no need to make the backup periodically.

### mtexec.exp is a script that can execute a MikroTik command remotely### it requires expect (install it with `yum install expect`)exec_mt_cmd=/usr/local/bin/mtexec.exp

### Make a backup of the MikroTik router and get it here.### Gets these parameters: server_ip passwd filenamefunction get_backup{ # get the parameters

Page 39: PPPoE With Mikrotik and Radius

server_ip=$1 passwd=$2 filename=$3

# make a binary backup of the MikroTik server $exec_mt_cmd "$passwd" "$server_ip" "/ system backup save name=MikroTik.backup"

# get it here wget "ftp://admin:$passwd@$server_ip/MikroTik.backup"

# copy it to the given destination filename mv MikroTik.backup $filename}

### get the backup of all the MikroTik serversget_backup 192.168.25.101 "mt-1" backups/MikroTik1.backupget_backup 192.168.25.102 "mt-2" backups/MikroTik2.backupget_backup 192.168.25.103 "mt-3" backups/MikroTik3.backup#get_backup 192.168.25.104 "mt-4" backups/MikroTik4.backup#get_backup 192.168.25.105 "mt-5" backups/MikroTik5.backup

The script /usr/local/bin/mtexec.exp is used to execute a MikroTik command remotely (see the section Executing MikroTik Commands From a Script  below). 

8.2 Database

A backup of the database of radius is made each night, however the backups older than a week are deleted automatically in order to free disk space. They can be downloaded from http://192.168.25.101/backup/radius_db/backups/ (by a script that uses wget, or manually) and then optionally can be written to another backup media (such as CD or DVD). 

The cron script that does this is /etc/cron.daily/backup-db.cron which is actually a symbolic link to /backup/radius_db/backup-db.cron . It just calls the script that makes the backup: 

#!/bin/bash### Make a backup of the database daily.### It should be linked to cron.daily like this: ### ln -s /backup/radius_db/backup-db.cron /etc/cron.daily/

/backup/radius_db/backup-db.sh

The script /backup/radius_db/backup-db.sh makes a full backup of the database and cleans any backups that are older than a week: 

#!/bin/bash### This script makes a full backup of the database.### It should be called periodically from a cron job.###### To restore, first unzip the backup file, and then use the command: ### bash$ mysql -p -u root < radiusdb.2007-10-27.sql

### go to this directorycd $(dirname $0)

### create a filename for the backup, which contains the datefilename="backups/radiusdb.$(/bin/date +%Y-%m-%d).sql"

Page 40: PPPoE With Mikrotik and Radius

### backup all the databases/usr/bin/mysqldump --user=root --password=sqladmin --all-databases --flush-logs \ --lock-all-tables --force --master-data=2 > $filenamegzip -f $filename

### find and clean any backup files older than a weekfind backups/ -ctime +7 | xargs rm -f

To restore a backup file, first unzip it, and then use the command: 

bash$ mysql -p -u root < radiusdb.2007-10-27.sql

8.3 Server

A backup of the data and configurations of the radius server can be done by the script /backup/radius_server/backup.sh . There is no need to do this backup periodically or automatically, it can be done manually whenever any modifications on the configuration are done. The files and directories that are backup­ed by the script are those that are listed in the file /backup/backup_server/backup-list.txt . 

The created backup archive can be retrieved remotely from http://192.168.25.101/backup/radius_server/ in order to store it to another backup media (such as CD, DVD, etc.). This backup can be used to build quickly another radius server that is almost identical as the original one (or to rebuild it in case of failure). 

● backup/radius_server/backup_server.sh

The script /backup/radius_server/backup_server.sh is used to backup the data and configurations of the server: 

#!/bin/bash### Backup the data and configurations in the radius server.### In case of failure, we should be able to setup the server by just### installing fedora7 and restoring the backup.

### go to this directorycd $(dirname $0)

### get a current list of the installed packages#rpm -qa | sort > pkglist.txt#rpm -qa | sed 's/-[0-9].*//' | sort > pkglist_1.txtyum list installed > pkglist.txtyum list installed | gawk '{print $1}' | sed 's/\.[^.]*$//' > pkglist_1.txt

### create a backup of the config files that are listed in 'backup-list.txt'echo radius-server-config.tgztar --create --gzip --preserve \ --files-from="backup-list.txt" --file radius-server-config.tgz

### create a backup of the directories /var/www/html/, /usr/local/, etc.echo radius-server-html.tgztar cz --preserve --file radius-server-html.tgz /var/www/html/echo radius-server-local.tgz

Page 41: PPPoE With Mikrotik and Radius

tar cz --preserve --file radius-server-local.tgz /usr/local/

● backup/backup_server/backup­list.txt

The file /backup/backup_server/backup-list.txt is a list of the files and directories that should be backup­ed: 

/etc/radiusmanager.cfg/var/www/html/radiusmanager/lic.txt/var/www/html/radiusmanager/config/config.php/etc/phpMyAdmin/config.inc.php/etc/my.cnf/etc/crontab/etc/cron.daily/backup-db.cron/etc/cron.daily/check-files.sh/etc/cron.monthly/backup-server.sh/etc/sysconfig/iptables/etc/resolv.conf/etc/aliases/home/dhoxha/.procmailrc/etc/rc.d/rc.local/etc/php.ini/etc/mail/sendmail.mc/etc/mail/sendmail.cf/etc/ntp.conf/etc/httpd/conf/httpd.conf/etc/httpd/conf.d/backup.conf/etc/httpd/conf.d/phpMyAdmin.conf/etc/httpd/conf.d/radiusmanager.conf/backup/mikrotik/backup.sh/backup/radius_db/backup-db.sh/backup/radius_db/backup-db.cron/backup/radius_server/backup-list.txt/backup/radius_server/pkglist.txt/backup/radius_server/pkglist_1.txt/backup/radius_server/backup-server.sh/usr/local/config//usr/local/etc/raddb//usr/local/bin/mtexec.exp/usr/local/scripts/

8.4 Rebuild the Server From Backup

The backup radius_server.tgz can be used to build quickly another radius server that is almost identical as the original one. It can be done like this: 

1. Initially install Fedora7 from CD/DVD. Install a system that is as small as possible (a minimal system, no need for GUI etc., just the base system). 

2. Transfer the backup file on the new system, using scp , wget or anything else. 

3. Make sure that in this system are installed almost the same packages as in the original server. It can be done like this: 

a. First update the packages that are already installed: 

Page 42: PPPoE With Mikrotik and Radius

bash# yum update

b. Then extract the pkglist_1.txt from the backup archive: 

bash# tar xfz radius-server.tgz backup/radius_server/pkglist_1.txt

c. Next, make sure that all packages in pkglist_1.txt are installed in the server: 

bash# cat backup/radius_server/pkglist_1.txt | xargs yum install

d. If you want, you can also make sure that no extra packages (more than those on the original server) are installed. It can be done by generating a list of the installed packages (using yum list installed ), comparing it to the file pkglist_1.txt (using diff ), finding out which are the extra packages and removing them: 

bash# yum list installed | gawk '{print $1}' | sed 's/\. [^.] *$//' \ >package_list.txtbash# diff -u package_list.txt pkglist_1.txt > pkg.diffbash# yum remove ...

However, extra packages in general should not harm anything. 

4. Now restore the backup file: 

bash# cd /bash# tar xvz --preserve --file radius_server.tgz

5. Don't forget to restore the database of radius manager. 

6. Also make sure that the needed services are ON (like httpd, mysqld, etc.), and those that are not needed are OFF. This can be done using the commands /sbin/chkconfig and /sbin/service . 

9 Misc

9.1 Keeping the Time Correct

It is important that the time of the server be correct, since radius manager checks the expiration times of the clients. In order to make sure that the time of the server is correct, we can use ntp. It can be installed and configured like this: 

1. Install the package ntp : 

bash# yum install ntp

2. Modify /etc/ntp.conf by adding time servers: 

Page 43: PPPoE With Mikrotik and Radius

# Use public servers from the pool.ntp.org project.# Please consider joining the pool (http://www.pool.ntp.org/join.html).server ntp1.altarisoluzione.comserver 0.fedora.pool.ntp.org dynamicserver 1.fedora.pool.ntp.org dynamicserver 2.fedora.pool.ntp.org dynamic

3. Start the service ntpd : 

bash# /sbin/chkconfig ntpd onbash# /sbin/service ntpd start

9.2 Executing MikroTik Commands From a Script

The script /usr/local/bin/mtexec.exp is used to execute a MikroTik command remotely. It requires expect (which can be installed with yum install expect ). It can be useful for automating things, since it can be called from another script, from a cron job, etc. 

#!/usr/bin/expect -f# Expect script to supply admin password for remote MikroTik server # and execute a command. This can be useful for automating things, # since it can be called from another script, from a cron job, etc.# This script needs three arguments:# password = the admin password of the MikroTik# ipaddr = the IP address of the MikroTik# command = the full MikroTik command that will be executed on the server# For example:# ./mtexec.exp mt 192.168.25.2 "ip address print" # -------------------------------------------------------------------------# This script is copied (and modified) from the nixCraft shell script # collection (NSSC) Visit http://bash.cyberciti.biz/ for more information.# ----------------------------------------------------------------------

### get the parameters set password [lrange $argv 0 0]set ipaddr [lrange $argv 1 1]set command [lrange $argv 2 2]set timeout -1

### connect to MikroTikspawn ssh admin@$ipaddrmatch_max 100000

### look for the password prompt and send the passwordexpect "*?assword:*"send -- "$password\r"

### look for the MikroTik prompt and send the commandexpect "*] >*"send -- "$command\r"

### logout from MikroTikexpect "*] >*"send -- "quit\r"

### send a blank line (\r) to make sure we get back to guisend -- "\r"

Page 44: PPPoE With Mikrotik and Radius

expect eof

9.3 Importing Clients Into the RM Database

A list of clients of a MikroTik can be generated by the command: 

/ ppp secret print detail file=user_list

Then it can be retrieved from MikroTik by FTP (for example: lftp [email protected] ). Then it can be processed using gawk , sed etc. in order to extract the useful information. 

Afterwards, the list of clients can be imported to RM using the script add-clients.sh (in directory /usr/local/scripts/import-clients ): 

#!/bin/bash### add clients in the database of radius manager

### go to this directorycd $(dirname $0)

### get the mysql connection parameters . db-cnn.shcnn="--host=$dbhost --database=$dbname --user=$dbuser --password=$dbpass"

### execute the query that is given as parametersfunction sql_exec{ query=$@ #echo "$query" ### debug echo "$query" | mysql $cnn}

### This function inserts into the database the data of a client.### It takes these arguments: username, password, service_id### and expiration_date. The other fields are set to default values.function add_client{ ### get the arguments of the function username=$1 password=$2 service_id=$3 expiration_date=$4

### build the queries that will insert the user data insert_into_rm_users=" INSERT INTO rm_users SET username = '$username' , password = MD5('$password'), srvid = '$service_id', expiration = '$expiration_date', enableuser = '1', createdon = NOW(), createdby = 'admin' " insert_into_radcheck=" INSERT INTO radcheck (UserName, Attribute, op, Value) VALUES ('$username', 'Simultaneous-Use', ':=', '1'),

Page 45: PPPoE With Mikrotik and Radius

('$username', 'User-Password', ':=', '$password') "

### execute the queries sql_exec "$insert_into_rm_users" sql_exec "$insert_into_radcheck"}

### add the clients in 'client-list.txt' into the database of RMfor user in $(cat client-list.txt)do echo adding client: $user add_client $user 123456 '2' '2008-01-15'done

The file db-cnn.sh contains the data that are needed to connect to the mysql database: 

### set the mysql connection parameters dbhost=192.168.25.101dbname=radiusdbuser=userdbpass=passw

The file client-list.txt has a list of usernames of the clients that will be imported: 

gerbitravelrezivdervishi. . . . . . . . .

9.4 Checking Client Expiration

Radius Manager had a small problem with client expiration: when a client service time limit is expired, but the the client is connected, the RM would not disconnect it. 

In order to fix it, we wrote a shell script that checks the database for the expired clients, disconnects them (if they are connected), and then sends a notification message to admin about the clients that are disconnected. It is located in /usr/local/scripts/check-expiration/: 

#!/bin/bash ### Check the expiration date of the clients, ### and disable and disconnect the expired clients.

### go to this directory cd $(dirname $0)

### get the mysql connection parameters . db-cnn.sh cnn="--host=$dbhost --database=$dbname --user=$dbuser --password=$dbpass"

### execute the query that is given as parameters function sql_exec { query=$@

Page 46: PPPoE With Mikrotik and Radius

#echo "$query" ### debug echo "$query" | mysql $cnn }

### get a list of the users that expire after 5 days query5="SELECT username FROM rm_users WHERE (NOW() + INTERVAL 5 DAY) >= expiration AND (NOW() + INTERVAL 4 DAY) <= expiration" user_list_5=$(sql_exec "$query5") user_list_5=${user_list_5#username} ## remove 'username' at the beginning

### get a list of the users that expired tonight query="SELECT username FROM rm_users WHERE expiration <= NOW() AND expiration >= (NOW() - INTERVAL 1 DAY)" user_list=$(sql_exec "$query") user_list=${user_list#username} ## remove 'username' at the beginning

### if the user lists are empty, exit if [ "$user_list_5" = "" -a "$user_list" = "" ]; then exit; fi

### send a message to the admin admin_email="root" msg_subject="[radius] Expired clients ($(date))" msg_body=" This is a list of the clients that expired tonight: $user_list

This is a list of the clients that expire after 5 days: $user_list_5 " echo "$msg_body" | mail -s "$msg_subject" "$admin_email"

### for each user in the expired list, disable and disconnect it if [ "$user_list" = "" ]; then exit; fi

mtexec=/usr/local/bin/mtexec.exp mtserver=192.168.25.121 mtpasswd='mt-1' mtprint="interface pppoe-server print detail without-paging" mtremove="interface pppoe-server remove"

str_user_list="" for user in $user_list do #echo $user ## debug

### add it to $str_user_list str_user_list="$str_user_list, '$user'"

### get the number of the user nr=$( $mtexec "$mtpasswd" $mtserver "$mtprint" \ | grep "user=\"$user\"" | cut -d' ' -f1 ) if [ "$nr" = "" ]; then continue; fi #echo $user $nr ## debug ### disconnect the user with this number $mtexec "$mtpasswd" $mtserver "$mtprint ; $mtremove $nr" >/dev/null done

### disable the expired users str_user_list=${str_user_list#, } query="UPDATE rm_users SET enableuser=0 WHERE username IN ($str_user_list)" #echo $query ## debug

Page 47: PPPoE With Mikrotik and Radius

sql_exec "$query"

db-cnn.sh:

### set the mysql connection parameters dbhost=192.168.25.121 dbname=radius dbuser=user dbpass=pass

This script is called periodically by cron each hour. In the file /etc/crontab we have added this line:

15 * * * * root /usr/local/scripts/check-expiration/check.sh

10 Referencies

10.1 PPPoE and RADIUS

PPPoE Server HOWTO for MikroTik RouterOS 2.9    

SQL HOWTO From ReeRADIUS Wiki    

How to setup up RADIUS for use with MikroTik ­ By Ramona    

PPPoE    

PPPoE Content    

RADIUS Client    

10.2 MySQL Replication

● Implementing two­way MySQL replication on live servers    

● How To Set Up Database Replication In MySQL    

● HOWTO: MySQL Replication    

● MySQL Replication HOWTO    

● MySQL Replication and Backup    

● MySQL 5.0 Reference Manual :: 15 Replication    

● MySQL Documentation    

Page 48: PPPoE With Mikrotik and Radius

10.3 Performance

● http://linux.derkeiler.com/Mailing­Lists/Fedora/2005­02/3149.html   

● http://linux.derkeiler.com/Newsgroups/linux.redhat.misc/2004­01/0220.html   

● Non­technical Guide to Isolating Slow MySQL Queries   

● http://www.databasejournal.com/features/mysql/article.php/3367871   

● http://www.debianhelp.co.uk/mysqlperformance.htm   

● http://www.databasejournal.com/features/mysql/article.php/10897_1382791_1   

11 GNU Free Documentation License

Version 1.2, November 2002 

Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.59 Temple Place, Suite 330, Boston, MA 02111-1307, USA

Everyone is permitted to copy and distribute verbatim copiesof this license document, but changing it is not allowed.

1. PREAMBLE 

The purpose of this License is to make a manual, textbook, or other functional and useful document free in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. 

This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. 

We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 

2. APPLICABILITY AND DEFINITIONS 

This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world­wide, royalty­free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. 

A "Modified Version" of the Document means any work containing the Document or a portion of 

Page 49: PPPoE With Mikrotik and Radius

it, either copied verbatim, or with modifications and/or translated into another language. 

A "Secondary Section" is a named appendix or a front­matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. 

The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. 

The "Cover Texts" are certain short passages of text that are listed, as Front­Cover Texts or Back­Cover Texts, in the notice that says that the Document is released under this License. A Front­Cover Text may be at most 5 words, and a Back­Cover Text may be at most 25 words. 

A "Transparent" copy of the Document means a machine­readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque". 

Examples of suitable formats for Transparent copies include plain ascii without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard­conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine­generated HTML, PostScript or PDF produced by some word processors for output purposes only. 

The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. 

A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition. 

The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. 

Page 50: PPPoE With Mikrotik and Radius

3. VERBATIM COPYING 

You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. 

You may also lend copies, under the same conditions stated above, and you may publicly display copies. 

4. COPYING IN QUANTITY 

If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front­Cover Texts on the front cover, and Back­Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. 

If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. 

If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine­readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer­network location from which the general network­using public has access to download using public­standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. 

It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 

5. MODIFICATIONS 

You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: 

A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. 

Page 51: PPPoE With Mikrotik and Radius

B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. 

C. State on the Title page the name of the publisher of the Modified Version, as the publisher. 

D. Preserve all the copyright notices of the Document. 

E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. 

F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. 

G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. 

H. Include an unaltered copy of this License. 

I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. 

J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. 

K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. 

L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. 

M.Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version. 

N. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section. 

O. Preserve any Warranty Disclaimers. 

If the Modified Version includes new front­matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. 

Page 52: PPPoE With Mikrotik and Radius

You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties­­for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. 

You may add a passage of up to five words as a Front­Cover Text, and a passage of up to 25 words as a Back­Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front­Cover Text and one of Back­Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. 

The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 

6. COMBINING DOCUMENTS 

You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. 

The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. 

In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements." 

7. COLLECTIONS OF DOCUMENTS 

You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. 

You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 

8. AGGREGATION WITH INDEPENDENT WORKS 

A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. 

Page 53: PPPoE With Mikrotik and Radius

If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 

9. TRANSLATION 

Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. 

If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 

10.TERMINATION 

You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 

11.FUTURE REVISIONS OF THIS LICENSE 

The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/. 

Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. 

ADDENDUM: How to use this License for your documents

To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: 

Copyright (C) year your name.Permission is granted to copy, distribute and/or modify this document

Page 54: PPPoE With Mikrotik and Radius

under the terms of the GNU Free Documentation License, Version 1.2or any later version published by the Free Software Foundation;with no Invariant Sections, no Front-Cover Texts, and no Back-CoverTexts. A copy of the license is included in the section entitled ``GNUFree Documentation License''.

If you have Invariant Sections, Front­Cover Texts and Back­Cover Texts, replace the "with...Texts." line with this: 

with the Invariant Sections being list their titles, withthe Front-Cover Texts being list, and with the Back-Cover Textsbeing list.

If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. 

If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.