📜 ⬆️ ⬇️

Free Wi-Fi with a little twist

This article tells about a small project of a free Wi-Fi network, about the main technical problems and solutions. The goal is to simply tell about a fairly original project.

A little less than a year ago, my management decided to deploy a free Wi-Fi network for visitors on the organization’s territory. Everything would be simple and prosaic if it were not for one interesting condition: before the user gets on the Internet, he should look at the information page, with our “advertisement”.

After a brief analysis, we came to the conclusion that this can only be done with a separate gateway server, most likely on Linux. A brief statement of work with a general description of the task distributed to companies involved in developing / implementing solutions at least close to this showed that when ordering an external solution, the cost of the project would skyrocket.
')
After much thought and fantasy on the topic: how to implement it (with immersion in the depths of the protocols, and dozens of erotic fantasies, how to replace packets, headers, etc.) a simple and logical solution was found.

Brilliant - just



Brief working principle:
  1. A user connecting to the network gets an ip-address using a regular dhcp-server. In the settings, our server is specified as the default gateway.
  2. The server has the following default iptables rule set:

    [root@wifi ~]# iptables -L -t nat
    Chain PREROUTING (policy ACCEPT)
    target prot opt source destination
    REDIRECT tcp -- anywhere !192.168.143.1
    DROP udp -- anywhere !192.168.143.1 udp dpt:!domain

    Due to this, all requests (except for DNS packets) from the user are redirected to the local server.
  3. When a user first attempts to load any web page, he gets to the local nginx server where the html page containing the string is displayed to him:
    <?php
    $run = "ts /usr/share/nginx/html/script.sh {$_SERVER['REMOTE_ADDR']}";
    exec($run);
    ?>

  4. And here begins the most interesting! This page starts the script lying on the server (passing it the client's ip-address as the launch parameter):

    #!/bin/sh
    LOG_FILE=/var/log/script_log
    {
    date | tr "\n" " "
    echo -n '|IP:'
    echo -n $1
    echo -n '|MAC:'
    /sbin/arp $1 -n | grep $1 | tr -s ' ' | cut -d ' ' -f 3 | tr "\n" " "
    mac=`/sbin/arp $1 -n | grep $1 | tr -s ' ' | cut -d ' ' -f 3 | tr "\n" " "`
    if ( sudo /sbin/iptables -n -L -t nat --line-numbers | grep $1 > /dev/null )
    then
    echo '|Rule exists!!'
    else
    echo -n '|Add rule '
    sudo /sbin/iptables -t nat --insert PREROUTING -s $1 -j ACCEPT
    echo -n '|Creat shedule:'
    echo "sudo /sbin/iptables -t nat -D PREROUTING -s $1 -j ACCEPT " | at -m now + 45 minutes
    sudo /usr/bin/python /usr/share/nginx/html/stat.py ${mac}
    fi
    } >> $LOG_FILE 2>&1


    Which makes two basic actions: adds a rule to iptables, and creates a deferred task in at.

    Rule:

    sudo /sbin/iptables -t nat --insert PREROUTING -s $1 -j ACCEPT

    It is placed in the PREROUTING chain to the first position, thereby being placed BEFORE the redirect rules. As a result, the user with this address gets full access to the Internet.

    The second main action, creating a rule at at:
    echo "sudo /sbin/iptables -t nat -D PREROUTING -s $1 -j ACCEPT " | at -m now + 45

    In essence, it limits the user's session to 45 minutes, after which the rule will be deleted and the user will again be redirected.


The scheme was implemented, tested, and proved its viability.

This would probably be worth finishing the story, but for “A little less than a year”, work was done to finalize the project, eliminate small jambs and add fairly original features.

Mentality



The first problem that arose was “abusers”. It was noticed that some particularly eager to freebies of a person use the network for an excessively long time. To identify these, it was decided to keep statistics. The main problem is that all billing systems (or simple modules for keeping statistics) consider the login or ip address to be the basic element. In our case, the first is simply not there, but it is impossible to be attached to the second, since ip-addresses are not static. The necessary statistics was based on the mac- address. After much research, no suitable solutions were found. Therefore, it was decided to invent another bike to write his own. Since it is essentially necessary and sufficient, it was necessary to count the number of sessions held by the mac-address by writing a simple script in python (unfortunately my knowledge of bash could not pull out this task):

import sys
file = open('/var/log/stat.file','r')
line = file.readlines()
line2 = ''
i = 0
while len(line) > i :
line2 = str(line[i])
line2 = line2.rstrip()
line2 = line2.split()
if line2[0] == str(sys.argv[1]) :
line2[1] = str(int(line2[1])+1 )
del line[i]
line.insert(i,line2[0]+' '+line2[1]+'\n')
break
i = i + 1
else :
line.append(str(sys.argv[1])+' '+'1'+'\n')
###########
file.close()
file = open('/var/log/stat.file','w')
file.writelines(line)
file.close()


Which was called from the main script. A section for this file with a weekly period has been added to logrotate. And in two weeks I would receive a list of "regular customers" whose mac-addresses were blacklisted on the switch installed in front of the server.

Bicycles will not pass!



The following problem was more original: when simultaneously running several scripts, one of them produced an iptables error (something from the “iptables: Unknown error 4294967295” series) without being executed. If it was a script to create a rule, then nothing terrible happened - the user simply updated the page and the script that was re-run was working without errors (of course, if he didn’t hit the simultaneous launch again, judging by the logs, once one poor thing was not very lucky and he was 5 times hit the simultaneous launch).
If the problem of deleting a rule took off with such an error, then the ip-address remained on the lists, and the user could sit on the Internet indefinitely and with impunity.

The first temporary solution came in the form of a simple bash-script that compares the list of addresses in iptables and the task pool at:

#!/bin/bash
LOG_FILE=/var/log/script_log
{
echo -n "Checking rules: "
date | tr "\n" " "
ar_ip=(`sudo iptables -L -t nat -n | grep ACCEPT | grep -v policy | cut -d ' ' -f 10 | tr '\n' ' '`)
ar_at=(`grep 168.143. /var/spool/at/* | cut -d ' ' -f 9 | tr '\n' ' '`)
count=${#ar_ip[@]}
for ((i=0; i <= count ; i++ ))
do
for h in "${ar_at[@]}"
do
if [[ ${ar_ip[$i]} == $h ]]
then
unset ar_ip[$i]
continue 2
fi
done
done
echo -n "|Delete rules: "
for i in ${!ar_ip[*]}
do
sudo /sbin/iptables -t nat -D PREROUTING -s ${ar_ip[$i]} -j ACCEPT
echo -n ${ar_ip[$i]} " "
done
echo "|Checking done"
} >> $LOG_FILE 2>&1


The script was placed in /etc/cron.hourly, and regularly removed the consequences of iptables errors. In principle, the solution was sufficient, but “there is no limit to perfection” and I began to surf the endless expanses in search of a better solution. And it was found. On one of the “cozy” linux forums, one of the mastodons pointed me towards this project.



In essence, this project is a small development for running bash scripts, putting them into a pool and performing in a strict sequence, one by one.
The script launch line on the web page has been modified to

ts /usr/share/nginx/html/script.sh {$_SERVER['REMOTE_ADDR']}

And iptables errors disappeared.

Problem three, or how I helped the open-source community



When the project was already working for about half a year, and people had already learned enough about it, another serious problem appeared: access points (Lynksys wap54g) began to spontaneously turn off / hang / reboot. Naturally the first thing that came to mind is to look at the logs. As it turned out, Lynksys are not in vain attributed to the "home" segment, because housewives read logs to nothing. The only thing that was contained in the logs is when a mac-address is connected. In addition, the log format was unique and the usual syslog server did not understand it. As always, Lynksys offered some kind of suspicious utility containing something magical in its name, supposedly capable of setting up your home network in an instant and instantly. After a brief study of the utility, it was concluded that it was unsuitable, and the long journey across the endless expanses began again. Somewhere in the endless steppes. On sf.net, a small project bent in 2009 was found (http://sourceforge.net/projects/wap54g-log/) which understood the format of the logs of points and was able to add them to a file. “And we don’t need more!” ©

It turned out that early rejoiced. The log entry was:

May 20 12:04:42 /usr/local/bin/wap54g-log[17544] Wireless PC connected 00:26:C7:61:BB:26

And it was impossible to understand which of the points the client connected to. And consequently, to make a conclusion about the load, as one and the most possible causes of unworthy behavior of points.
And then I had to remember S. As it turned out, not to recall, but to study anew, because what was written in the second year at the institute in Visual Studio only remotely resembled the code of this small utility.

After a thoughtful reading, the structure of theiraddr was found, referring to the sockaddr _in type (the standard for unix socket type) which contains another in_addr structure which contains a single s_addr variable of the in_addr_t type. “Egg in a duck, duck in a hare, hare in shock” ©. The most fun was the comment "The fact that such a structure is used, and not just a variable of type in_addr_t, has developed historically."

Going deeper and deeper, the library <arpa / inet.h> (Oh, God! Ghost arpa!) Was found containing functions for working with these structures. By converting the function inet_ntoa (strcu) and putting it all into the output of the utility, it turned out something like this:

May 20 12:23:38 192.168.143.114 /usr/local/bin/wap54g-log[17544] Wireless PC connected 00:26:C7:61:BB:26

The key difference is the availability of the address point. Those. Now you can judge the distribution of load points.
As it turned out intuition / logic / 5th point, I did not let me down. And after small observations, it turned out that the Wap54g does not even support 30 simultaneously connected users.

This problem has yet to be resolved. So far, there are no options other than replacing points with something more “industrial”. The management decides what to do, and a letter was sent to the developer of the utility with thanks and suggestions for improvement.

There were also smaller problems: nginx produced 404 pages, if the address from which the redirect occurred, contained the name of the page and a get request in the address bar. It was solved in one line in the virtual server configuration “rewrite ^ / (. *) /Index.php last;”. But you should not talk about such trifles here. they are all banal and everyday.

Instead of conclusion



The final decision on writing this article was confirmed after reading a couple of articles "How to become a system administrator - a guide for beginners." I do not consider myself to be any kind of guru, I soberly understand that I am a system administrator of the middling linux-orientation. This article shows only a small part of the amount of knowledge that is necessary for everyday work. Just html, bash, python, and a little knowledge of C. Well, as a mandatory base: knowledge of the theory (all of IT, from networks to programming), and the OS (utilities, system applications) with which you basically have to work. I think this will be a good addition.

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


All Articles