Pages

Κυριακή 23 Ιουνίου 2013

NoIP στο Raspberry Pi και μείωση του Internet TrafficNoIP in Raspberry Pi and Internet Traffic Reduction

Εισαγωγή

Introduction

Πολλές φορές χρειαζόμαστε να στήσουμε κάποιου είδους server έτσι ώστε να μπορούμε να έχουμε πρόσβαση σε αυτόν από τον "έξω κόσμο", δηλαδή από παντού, όπου υπάρχει πρόσβαση στο διαδίκτυο. Το πρόβλημα σε αυτό είναι πως οι περισσότεροι πάροχοι Internet (Internet Service Providers, εν συντομία ISPs) δε δίνουν σταθερή διεύθυνση IP στα router που έχουμε σπίτι μας (εκτός, φυσικά, αν το ζητήσουμε με κάποια παραπάνω χρέωση). Έτσι, θα πρέπει κάθε φορά να γνωρίζουμε την IP διεύθυνση του router μας για να μπορέσουμε να έχουμε πρόσβαση στον server που κάθεται πίσω από αυτό. Αυτόν ακριβώς το σκοπό έχει και το παρόν άρθρο. Τι θα λέγατε όμως, αν το σύστημα που θα μας βοηθούσε είναι ένα Raspberry Pi; Όχι πως αυτά που περιγράφονται εδώ δε μπορούν να εφαρμοστούν και σε άλλο σύστημα υπολογιστή... Αντιθέτως, ένα δυνατό σημείο του ανοικτού λογισμικού, είναι πως η διαχείρισή του γίνεται με τον ίδιο ακριβώς τρόπο, είτε αυτό τρέχει σε ένα μηχάνημα με 64 επεξεργαστές, είτε τρέχει σε μια... τοστιέρα (βλ. NetBSD!).

There are sometimes that we need to setup a small server in a way to have access to it from the "outer world", meaning everywhere, wherever there is internet access. The problem is that most of the Internet Service Providers (abbreviated as ISPs) do not give static IP address to our home routers (unless of course, we ask for it, in extra charge). So, we have to know the IP address of our router in order to gain access to our server behind it. This is the goal of this article. But, what if the helper system for our purpose is a Raspberry Pi? Not that what is described in here cannot be applied to some other computer system... Contrariwise, this is a very powerful part of opensource; the administration and setup of a system is a similar way, whether it runs on a 64 core system, or even a... toaster (see NetBSD site!).

Τι θα δούμε

What is in this article

Παρότι το άρθρο προορίζεται σε ανθρώπους που ξέρουν να ρυθμίζουν routers, να στήνουν servers, να διαχειρίζονται υπηρεσίες σε λειτουργικά όπως το Linux και να έχουν τη δυνατότητα, ίσως, να ασχοληθούν με ένα gadget του τύπου Raspberry Pi, εν τούτης θα δοθούν πληροφορίες ακόμα και σε πιο "αρχικά" πράγματα. Μέσα σε όλους τους σκοπούς του άρθρου είναι να μπορέσει ακόμα και κάποιος αρχάριος να βρει κάποιες εναρκτήριες πληροφορίες, εισαγωγικές περισσότερο σε όλα αυτά με τα οποία σχετίζεται η πρόσβαση ενός υπολογιστή σε ένα άλλο, μέσω του διαδικτύου. Ακόμα και για την πληρότητα του άρθρου, δε θα μπορούσαν να λείπουν αυτές οι πληροφορίες. Αν είστε κάπως πιο προχωρημένος χρήστης/γνώστης και κάποια παράγραφος σας είναι απλή ή δεν προσφέρει κάποιες παραπάνω γνώσεις σε αυτές που ήδη έχετε, μπορείτε ασφαλώς να την προσπεράσετε και να μπείτε στο "ψητό" της ιστορίας.

Though this article is for people who know how to setup a router, servers, administrate services in operating systems such as Linux and have the ability, perhaps, to deal with a gadget of Raspberry Pi's type, yet, the information in here will be in a novice level. Between the article's goals is for a not so advanced user to find some basic steps in all these stuff that communication between two computers through the internet, involves. Even for clarity, some of these information could not be omitted. If you are more advanced user and you find that some paragraphs do not contribute to your knowledge, feel free to skip it and proceed to the "hot point" of the story.

Μια μικρή περίληψη όσων θα δούμε μέσα στο παρόν άρθρο:

A brief of what we will find is:

DNS, Ευρετήριο διευθύνσεων διαδικτύου

DNS, Domain names index of the internet

Κάθε υπολογιστής ή άλλη συσκευή που συνδέεται στο διαδίκτυο με σκοπό να ανταλλάξει πληροφορίες διαμέσου αυτού, παίρνει μια μοναδική διεύθυνση στον κόσμο. Αυτή είναι και η βασική ιδέα. Αυτή την ονομάζουμε διεύθυνση IP. Φυσικά και υπάρχουν διευθύνσεις που θα τις δούμε να υπάρχουν ταυτόχρονα σε πολλούς υπολογιστές (π.χ. μια διεύθυνση της μορφής 192.168.1.1), αλλά ας μείνουμε στη βασική ιδέα του συστήματος του διαδικτύου και ας μην επεκταθούμε σε τέτοιες λεπτομέρειες. Το router που έχουμε στο σπίτι μας ή στο γραφείο μας (ή οπουδήποτε, τέλος πάντων) είναι και αυτό μια συσκευή επικοινωνίας που συνδέεται με το διαδίκτυο. Κατά συνέπεια και αυτό έχει μια διεύθυνση IP. Γιατί γίνεται αυτό; Αυτή η διεύθυνση είναι ένα κομμάτι της "ταυτοποίησης" του αντικειμένου. Όταν γίνεται μια επικοινωνία = μεταφορά δεδομένων από ένα σύστημα σε ένα άλλο, τότε απλά οι διευθύνσεις είναι αυτές που καθορίζουν τον αποστολέα και τον παραλήπτη. Όπως ακριβώς και η μεταφορά αλληλογραφίας με το κανονικό ταχυδρομείο που χρειάζεται να φέρει ο φάκελος τις διευθύνσεις αποστολέα και παραλήπτη.

Every computer or other network device that is connected to the internet with the purpose of exchanging data through it, must have a unique address all over the world. That's the basic idea. This is the address we call "IP Address". Of course we will find IP addresses that exist in more than one computer at the same time (ie. an address of type 192.168.1.1), but lets stick on the basic idea of the internet's system and not expand to such details for now. The routing device (called router) we have at home or office (or wherever) is a communication device that is connected to the internet. So, it also has an IP address. Why that happens? This address is used for some kind of identification of this device. When a communication takes place = data transfer from one system to another, the addresses identify who is the sender and to who is the target, in all over the network; similar to the way mail transfer takes place at the ordinary post office; the envelope has both the sender's and the recipient's address.

Οι διευθύνσεις που δίνονται σε όλα αυτά τα συστήματα επικοινωνίας, είτε είναι υπολογιστές είτε είναι ένας δικτυακός εκτυπωτής κ.λ.π, έχουν τη μορφή 4 αριθμών χωρισμένων από τελείες (.). Ο κάθε αριθμός μπορεί να πάρει τιμές από 0 μέχρι και 255. Υπάρχει και ένας πιο σύγχρονος τρόπος διευθυνσιοδότησης, όπου η κάθε διεύθυνση αποτελείται από 8 τετραψήφιους δεκαεξαδικούς αριθμούς χωρισμένους από άνω-κάτω τελείες (:).

The given addresses to all these communication and networking devices, whether they are computers or network printers etc., they consist of 4 numbers separated by dots (.). Each number cat take a value from 0 to 255. There is also a newer way of addressing where the address is formed by 8 four-digit hexadecimal numbers separated by colons (:).

Και γιατί τα αναφέρουμε όλα αυτά; Βλέπετε πουθενά λέξεις, όπως google.com, blogspot.gr ή my_really_really_fancy_site.biz; Όχι, γιατί ΔΕΝ ΥΠΑΡΧΟΥΝ. Αυτό σημαίνει πως για να μπορέσουμε να επισκεφθούμε τη μηχανή αναζήτησης της Google, το site που φιλοξενεί τα περισσότερα blogs ή μια άλλη τοποθεσία με το πιο σημαντικό υλικό που μας ενδιαφέρει (λέμε τώρα!) θα έπρεπε να θυμόμαστε ένα σωρό νούμερα που να δώσουν στον browser μας να καταλάβει ποια τοποθεσία θέλουμε να δούμε. Λίγο δύσκολο ε;... Ναι. Και για να μπορέσουμε να βρούμε τοποθεσίες στο internet θα έπρεπε να έχουμε ένα τεράστιο κατάλογο με αντιστοιχία διευθύνσεων σε ονόματα των site που αντιστοιχούν, ή ιδιότητες των site κ.λ.π. Και κάθε φορά που θα θέλαμε να επισκεφθούμε μια τοποθεσία θα έπρεπε να κατεβάζουμε τον αντίστοιχο τόμο από τη βιβλιοθήκη μας και να τον ψάχνουμε, μέχρι να βρούμε αυτή την τοποθεσία που ψάχνουμε... Ακόμα χειρότερα, κάθε φορά που ένα καινούργιο site θα δημιουργόταν στο διαδίκτυο, θα έπρεπε να ανανεώσουμε το ράφι με αυτούς τους καταλόγους!

And why do we point all of these? Do you see words like google.com, blogspot.gr or my_really_really_fancy_site.biz anywhere? No, because THEY DO NOT EXIST. In order to visit Google's search engine, the site that contains many blogs or another web site we are interested in, we have to remember a lot of numbers that will give our browser the information of which site we want to visit. Kind of hard, isn't it?... Yeap!. And in order to be able to find out some websites later we should own a really huge index that should have a one to one correlation between addresses and site names or site properties etc. And every time we would like to visit a site we should take the corresponding volume from our library and search through it untili we find tyhe desired site... There's even worse, every time a new site appeared in the total network, we should update the index!

"Χμμμ... Μα εγώ δε θυμάμαι να δίνω τέτοια νούμερα που αναφέρεις στον browser μου...". Επειδή ακριβώς το να θυμόμαστε νούμερα είναι πολύ δυσκολότερο από το να θυμόμαστε λέξεις, για να μη μπαίνουμε στον κόπο να ψάχνουμε τις διευθύνσεις που πρέπει να δώσουμε για να μπορέσουμε να προσπελάσουμε τον κάθε ιστότοπο που επιθυμούμε, έχουν δημιουργηθεί κάποιοι servers οι οποίοι κάνουν ακριβώς αυτό· αντικαθιστούν το τεράστιο ράφι της βιβλιοθήκης μας, που λέγαμε πριν... Τους δίνουμε ένα όνομα ιστότοπου και αν αυτό υπάρχει μας επιστρέφουν διεύθυνση IP στην οποία βρίσκεται ο εν λόγω ιστότοπος. Αλλά μπορούν να κάνουν και το αντίθετο, δηλαδή να μας πουν το όνομα του ιστότοπου στον οποίο οδηγεί μια διεύθυνση.

"Hmmm... But I don't remember specifying such numbers in my browser...". Due to the difficulty in remembering numbers compared to remembering words, in order not to try to search through IP addresses every time we need to access a site, there are some servers they perform this action for us: They replace the huge library shelf we were talking about... We can send them the site name we want to access and they return the IP address the web site in question lies. But they can also perform the reverse function; they can tell the name of the website an IP address points to.

Διαδικασία ονοματοδοσίας

Naming

Και το ερώτημα είναι πώς γίνεται μια ονοματοδοσία στον τεράστιο χώρο του internet; Όταν κάποιος θελήσει να στήσει ένα server στο διαδίκτυο, τότε θα πρέπει να κατοχυρώσει ένα όνομα, το οποίο όλοι οι υπόλοιποι θα χρησιμοποιούν για να έχουν πρόσβαση σε αυτή την υπηρεσία που προσφέρει ο εν λόγω εξυπηρετητής. Αυτό το όνομα είναι μοναδικό. Αφού κατοχυρωθεί το όνομα, σε κάποιο server του διαδικτύου, μπορεί να φιλοξενηθεί η ιστοσελίδα ή η υπηρεσία που μας ενδιαφέρει. Ο server αυτός έχει κάποια συγκεκριμένη διεύθυνση IP. Μπορεί να ανήκει σε κάποια εταιρία φιλοξενίας (hosting) ιστοσελίδων, ή ακόμα και στον υπολογιστή που έχουμε στο σπίτι μας! Το τελευταίο βήμα, είναι να "παντρέψουμε" το όνομα που κατοχυρώσαμε με τη διεύθυνση στην οποία βρίσκεται η εν λόγω ιστοσελίδα/υπηρεσία· αυτή, συνήθως, τη φτιάχνουμε εμείς.

And the question now is how the naming of the sites happen throughout the huge internet space? If someone wants to set a server in the internet, he must first register a name, the one that all the others will use to be served by the server in question. This name must be unique. After the registration of the name, another server must host the web page or the needed service to be offered. That server must have a specific IP address. It can be owned by a web hosting company, or can be even the computer we have at our place! The final step is to tie together the name and the IP address in question. The web page or the service is the one that we create.

Πού βρίσκεται το πρόβλημα; Όταν το μόνο που μας ενδιαφέρει είναι να έχουμε ένα ωραιότατο server για δική μας δουλειά, θα πρέπει να κατοχυρώσουμε ένα όνομα στο διαδίκτυο (=κόστος), να πληρώσουμε σε κάποια εταιρία hosting χώρο που να τον διαμορφώσουμε κατάλληλα ώστε να φιλοξενήσει την υπηρεσία που μας ενδιαφέρει (=κόστος) και τέλος να δηλώσουμε σε κάποιο DNS ότι το όνομα που κατοχυρώσαμε "δείχνει" στον server της εταιρίας hosting (=κόστος) η οποία φιλοξενεί την υπηρεσία μας... Εναλλακτικά, μπορούμε να πληρώσουμε τον ISP μας για να μας δώσει σταθερή IP διεύθυνση, οπότε τη φιλοξενία της υπηρεσίας μας την κάνουμε στον υπολογιστή στο σπίτι μας. Όλα αυτά μας επιβαρύνουν οικονομικά.

Where the problem is? If the only thing that matters is to have a nice personal server, for our personal usage only, we should buy an internet domain name (=added cost), pay a hosting service company to give us space in their servers, configure that space to host our service (=added cost) and finally submit the new domain name in a DNS pointing the IP address of the host server (=added cost, again) that serves our service... Also an alternative is to pay our ISP to give us a static IP address, so we can use our own computer to serve whatever we want from our home. But all these cost us money.

Το ερώτημα είναι: «Αφού δεν κάνω επαγγελματική ιστοσελίδα, αλλά με ενδιαφέρει να έχω πρόσβαση στο δίκτυό μου για τη δική μου διευκόλυνση και μόνο. Δε μπορώ να το κάνω χωρίς κόστος;» Αυτό που χρειαζόμαστε είναι μια υπηρεσία που να μπορεί να μας αντιστοιχεί μια δυναμική διεύθυνση σε ένα σταθερό όνομα.

The question is: "Since I don't service a professional web page, but I just want to have access to my own home network for my convenience and only, does it have to cost me that much?". In that case what we really need is a web service that can bound a static domain name to a dynamic IP address, just as a normal DNS server does.

Δυναμικός DNS για δυναμικές IP

Dynamic DNS for Dynamic IP addresses

Αυτή είναι μια υπηρεσία που πλέον βρίσκεται αρκετά στο διαδίκτυο. Η εγγραφή σε μια υπηρεσία δυναμικού DNS είναι μια απλή λύση στο πρόβλημά μας. Οι περισσότερες δυναμικές DNS υπηρεσίες που προσφέρονται από κάποια sites, θέλουν να έχει κάποιος ένα κατοχυρωμένο όνομα. Άλλες πάλι, αφήνουν τον χρήστη να επιλέξει από μια σειρά ονόματα που έχει διαθέσιμα. Ένα χαρακτηριστικό παράδειγμα είναι το DynDNS.

This is a service that can be found nowadays on the internet. The registration in a Dynamic DNS service is a simple solution to our problem. Most of the Dynamic DNS services available through some sites, just need someone to have a registered domain name. Some other, let the user select one from the available to that site domain names. An example is DynDNS.

Το DynDNS είναι ένα site που προσφέρει υπηρεσίες δυναμικού DNS. Ο χρήστης έχει τη δυνατότητα να χρησιμοποιήσει ένα όνομα της αρεσκείας του, αρκεί αυτό να ανήκει σε domains που ανήκουν στην ίδια τη DynDNS. Παράδειγμα, ένας χρήστης θα μπορούσε να χρησιμοποιεί το όνομα eliasfiles.dyndns-at-home.org γιατί ανήκει στο domain της DynDNS (dyndns-at-home.org). Το καλό που έχει το DynDNS είναι πως τα περισσότερα, πλέον, routers έχουν ενσωματωμένη την υποστήριξη για τη συγκεκριμένη υπηρεσία. Όμως, τον τελευταίο καιρό το site άρχισε να προσφέρεις τις υπηρεσίες του με πληρωμή. Πιο συγκεκριμένα, ένας καινούργιος χρήστης είναι υποχρεωμένος να δοκιμάσει την υπηρεσία DynDNSPro ελεύθερα για 14 ημέρες και αν δεν τη διακόψει νωρίτερα τότε χρεώνεται για τη χρήση της. Αυτό του δίνει το δικαίωμα να έχει την υπηρεσία για ένα χρόνο. Αν τη διακόψει πριν τη 14η ημέρα, τότε δε μπορεί να έχει καθόλου υπηρεσίες DynDNS. Για κάποιον ο οποίος θέλει να έχει πρόσβαση σε κάποια αρχεία του, κάποια βάση δεδομένων με δικές του πληροφορίες κ.λ.π. δεν είναι ότι καλύτερο να πρέπει να πληρώσει για κάτι το οποίο δεν του αποφέρει καθόλου κέρδος.

DynDNS is a site that offers Dynamic DNS services. The user has the ability to use a domain name he/she likes, provided that this name belongs to domains that really belong to DynDNS itself. For example, a user could use eliasfiles.dyndns-at-home.org because it belongs to a registered DynDNS domain. The good part is that most of the routers available for home usage can be configured to use this service. But, lately the site started to offer their services with a cost. More specifically, a new user is forced to test the DynDNSPro service free of charge for 14 days only. If he/she does not stop using it then, after the 14th day a small fee is charged for one more year usage. If he/she stops using the service then there will be no more DynDNS services. For someone who wants to have access to his files, a personal database having his own data etc, it is not the best idea to pay for something that does not offer him some income.

NoIP: Υπηρεσία δυναμικού DNS για όλους

NoIP: Dynamic DNS Services for all

Αρκετό ψάξιμο στο internet μου εμφάνισε σελίδες που προσέφεραν υπηρεσίες δυναμικού DNS, αλλά σε όλες έπρεπε να έχει κάποιος κατοχυρωμένο domain name. Τελικά, μια από όλες μου τράβηξε περισσότερη την προσοχή, η NoIP. Αυτή η σελίδα προσφέρει υπηρεσίες δυναμικού DNS, αλλά και ελεύθερης κατοχύρωσης ονόματος που θα ανήκει στο domain no-ip.biz (και άλλα). Κάτι παρόμοιο, δηλαδή, με το παλιό καλό DynDNS.

After a log search through the internet there were many web sites offering Dynamoc DNS services, but they needed the user to have a domain name already registered. Finally, one of them just paid my attention, NoIP. That web page offers Dynamic DNS, but also gives the ability to use a NoIP registered domain name that belongs to no-ip.biz (and many more). It is something similar to DynDNS.

Τι άλλο προσφέρει η NoIP:

What else does NoIP offer:

  • Ελεύθερο (χωρίς χρέωση) Domain Name που ανήκει στο no-ip.biz (ή κάποιο άλλο από τα προκαθορισμένα του)
  • Free of charge (no cost at all) Domain Name that belongs to no-ip.biz (or another that belongs to NoIP list)
  • Έναν client που αναλαμβάνει την ενημέρωση της λίστας του DNS με την καινούργια IP. Αυτόν τον ονομάζει DUC - Dynamic Update Client (περισσότερα ακολούθως)
  • A client program that updates the DNS database with the new IP when there is an IP address change from our ISP. They call it DUC - Dynamic Update Client (more on this later)
  • Ο DUC είναι ανοιχτού κώδικα
  • DUC is open sourced!
  • Οδηγείες για τη δημιουργία δικού μας client αν δε μας αρέσει ο δικός της
  • There are also information on how to create our own update client if for some reason we don't like theirs

Ο NoIP Client είναι ένα πρόγραμμα που τρέχει στον υπολογιστή μας και ανά τακτά διαστήματα ανιχνεύει τη διεύθυνση που έχουμε από τον ISP και αν δει ότι διαφέρει από την προηγούμενη, ενημερώνει τον DNS Server της NoIP για την καινούργια διεύθυνση. Έτσι, το όνομα το οποίο έχουμε κατοχυρώσει δείχνει στην καινούργια μας διεύθυνση. Το ίδιο ακριβώς σύστημα έχει και το DynDNS με ένα πρόγραμμα client που ονομαζόταν ddclient.

NoIP Client is a small program that runs in our computer and at regular intervals it checks for our IP address the ISP has set and if it is different from the one we had earlier, then it updates NoIP DNS server. So, the domain name we have registered points to our new IP address. DynDNS laso uses the same updating system, using a client called ddclient.

Πλεονεκτήματα της χρήσης ενός client προγράμματος είναι ότι αυτός τρέχει σε έναν υπολογιστή και ενημερώνει τη NoIP για τις αλλαγές της IP διεύθυνσης χωρίς να χρειάζεται να κάνει κάτι ο χρήστης.

The advantage of using an update client program is that it runs in a computer at the background and informs NoIP whenever there is an IP address change, without user's intervention.

Μειονεκτήματα της χρήσης ενός client είναι πως ο client λειτουργεί μόνο όση ώρα είναι σε λειτουργία ο υπολογιστής που τον τρέχει. Συνεπώς, υπάρχει η περίπτωση να πρέπει να έχουμε ένα υπολογιστή ενεργοποιημένο 24 ώρες το 24ωρο. Ο client ελέγχει για αλλαγή διεύθυνσης ανά τακτά διαστήματα. Τέτοια αλλαγή μπορεί να γίνει οποιαδήποτε ώρα και στιγμή από τον provider. Αυτό οδηγεί στο δεύτερο μειονέκτημά, πως από τον χρόνο που θα εκτελέσει ο ISP μια αλλαγή στη διεύθυνσή μας μέχρι τη στιγμή που ο client θα ελέγξει για μια τέτοια κατάσταση, ο DNS θα έχει την παλιά μας διεύθυνση και έτσι δε θα μπορούμε να έχουμε πρόσβαση στον server μας γι' αυτό το χρονικό διάστημα. Τέλος, ο client για να ανιχνεύσει την αλλαγή της διεύθυνσης, στέλνει ένα request στο server της NoIP. Αυτό σημαίνει διακίνηση δεδομένων στο διαδίκτυο, κατά συνέπεια δε μπορούμε να ρυθμίσουμε τον client να κάνει τον έλεγχο σε πολύ τακτά χρονικά διαστήματα (π.χ. 5 δευτερολέπτων). Χρήση τακτικών ελέγχων βοηθάει στο να μειώσουμε το χρόνο της ασυμφωνίας της διεύθυνσης που έχει ο DNS με την πραγματική μας, μετά από αλλαγή από τον ISP. Ταυτόχρονα, όμως, αυξάνει και τη διακίνηση πληροφορίας προς τον NoIP server. Αποτέλεσμα είναι να κινδυνεύουμε να μας κάνει τελικά ban ο server και να μη δέχεται τις πληροφορίες μας, διότι θεωρεί ότι του κάνουμε ηλεκτρονική επίθεση.

The drawback of using such a client is that it works only when the computer that runs it is powered on. Thus, we may have to keep our computer running 24 hours a day. The client checks for an address change at regular intervals. An IP address can be performed by the internet provider any time. This leads to a second drawback. From the time the ISP changes our IP address till the time the update client does its job, the DNS servers over the internet will have our old IP address, so we will not be able to access our server during that time. Finally, the client tracks the address change by sending a request to NoIP server. This, in turn, means internet traffic, so we cannot configure the client to use a small update interval (such as 5 seconds). The small updating interval helps having a small lag during IP address change and DNS tables updating. But, at the same time increases the traffic to NoIP server. This could make NoIP server to ban us and ignoring information send by our update client, because it could thing we perform an electronic attack.

Γιατί το Raspberry Pi;

Why Raspberry Pi?

Το Raspberry Pi είναι ένας μικρός υπολογιστής μεγέθους πιστωτικής κάρτας (όχι δε μπορείτε να κάνετε πληρωμές σε καταστήματα με αυτό! :)) βασισμένος σε αρχιτεκτονική επεξεργαστή ARM. Καταναλώνει ελάχιστα και τρέχει οποιαδήποτε διανομή Linux (ή ακόμα και FreeBSD) είναι μεταγλωττισμένη γι' αυτή την αρχιτεκτονική. Είναι πολύ βολικό για τέτοιες καταστάσεις.

Raspberry Pi is a small computer at the size of a credit card (well, no, you cannot perform in shop payments using it! :)) based on ARM architecture. It consumes little power and can run any Linux distribution (or even FreeBSD) that is compiled for that architecture. It is very convenient for cases like ours.

Επίσης, δεν υπάρχει λόγος γιατί να πρέπει να λειτουργεί 24/7 ένας υπολογιστής (εκτός και αν είναι απαραίτητο για άλλους σκοπούς). Το Raspberry Pi λόγω της μικρής του κατανάλωσης, αλλά και του μικρού του μεγέθους, μπορεί να λειτουργεί συνεχώς, χωρίς πρόβλημα, ενώ δεν πιάνει χώρο επάνω σε ένα γραφείο, όπως τα PC. Μπορεί να μπει δίπλα από το router μας (κάποια από αυτά διαθέτουν και μια USB θύρα και μπορούν να το τροφοδοτήσουν), ενώ υπάρχουν αρκετά όμορφα κουτάκια τα οποία το κάνουν να δείχνει σοβαρό σε οποιοδήποτε χώρο (μη φωνάζει η γυναίκα πως δεν ταιριάζει με τις κουρτίνες :Ρ).

There is no reason why a PC computer should be on 24/7 (unless it must be on for specific services). Because Raspberry Pi consumes so little power and because of its small size, it can be powered on without problems, and at the same time it has small footprint on our desktop, unlike PCs. It can live side by side with our router (some of them having USB connectors can also power it). There are also some very good looking boxes for it, making suitable for the space it lives in our house (not to let your wife comlain that it does not suit with the curtains of the room :Ρ).

Όσα περιγράφονται στο παρόν άρθρο έχουν γίνει επάνω στο λειτουργικό Raspbian που είναι βασισμένο στο Debian. Επειδή, όμως, οι διανομές Linux έχουν πάρα πολλά κοινά μεταξύ τους, δεν υπάρχει λόγος γιατί, με έστω λίγες αλλαγές, να μη μπορούν να τρέξουν και σε οποιαδήποτε άλλη διανομή για οποιαδήποτε αρχιτεκτονική.

What is described in this article is done in Raspbian operating system which is based on Debian. But, since Linux distributions share a lot in common, there is no particular reason why, even with small changes, they cannot be done in other distribution or architecture.

Ο Dynamic Update Client της NoIP

NoIP Dynamic Update Client

Η NoIP δίνει έναν client για το update της διεύθυνσης IP στον DNS τους, ο οποίος είναι γραμμένος σε γλώσσα C. Για απλή χρήση είναι αυτό που χρειάζεται κάποιος. Μπορείτε να τον κατεβάσετε και να τον κάνετε compile κανονικά, όπως και κάθε άλλο πρόγραμμα. Στο Raspberry Pi γίνεται κανονικά compile, ενώ τρέχει χωρίς κανένα πρόβλημα.

NoIP provides an update client for updating their DNS server with our new IP address. It is written in C language. For a simple use it is what anybody needs. You can download and compile it normally, as any other program that can be installed from its source code. In Raspberry Pi its compilation and execution runs flawlessly without any problems.

Η εγκατάσταση είναι απλή. Αρχικά κατεβάζετε τον πηγαίο κώδικα, μιας και είναι opensource, από το site της NoIP. Στη συνέχεια αποσυμπιέζετε το αρχείο:

The installation is very simple. First you download the program's source code, since it is opensource, from NoIP site. The decompression follows:

pi@raspberrypi:~ > tar -xvzf noip-duc-linux.tar.gz
...
pi@raspberrypi:~ > 

Αυτό θα δημιουργήσει ένα κατάλογο με όνομα noip-version. Μέσα σε αυτόν βρίσκεται όλος ο πηγαίος κώδικας, scripts για διάφορες διανομές ώστε να λειτουργέι σαν υπηρεσία κ.λ.π. Μπορείτε ελεύθερα να περιηγηθείτε μέσα στα περιεχόμενα του καταλόγου. Όταν τελικά αποφασίσετε να το εγκαταστήσετε κάνετε τα ακόλουθα: (η έκδοση που βρίσκεται ο DUC τη στιγμή που γράφεται το άρθρο είναι η 2.1.9-1)

A directory named noip-version will be created. In there you can find the source code, service scripts for some distributions, etc. You can freely browse through the contents of the directory. When you finally decide to install it just do the following: (The version of DUC the time this article is edited is 2.1.9-1)

pi@raspberrypi:~ > cd ~/noip-2.1.9-1
pi@raspberrypi:~ > make
...
pi@raspberrypi:~ > sudo make install
...
pi@raspberrypi:~ > 

Αυτές οι εντολές θα εγκαταστήσουν το noip2 στον κατάλογο /usr/local/bin. Οι πληροφορίες που δίνονται στα διάφορα αρχεία README.FIRST είναι αρκετές για να το χρησιμοποιήσετε.

These commands will install noip2 in /usr/local/bin directory. The provided information by various files like README.FIRST are enough to make you use it.

Μιας και τα μειονεκτήματα του DUC τα είδαμε πριν, ας προχωρήσουμε σε μια διαφορετική υλοποίηση από αυτή του NoIP DUC που βελτιώνει κάποια χαρακτηριστικά.

Since we presented the drawbacks of DUC earlier, lets proceed to a different implementation than that of NoIP's DUC, that improves it.

Μείωση του Internet Traffic

Internet Traffic Reduction

Η μεγαλύτερη διακίνηση πληροφορίας που γίνεται στο Internet από τον client είναι για την εύρεση της IP διεύθυνσης που μας έχει δώσει ο provider μας. Κάθε φορά που ο DUC θέλει να μάθει την IP μας, υποβάλει ένα ερώτημα στον server της NoIP. Αυτός βλέπει από ποια IP γίνεται το ερώτημα και την επιστρέφει στον DUC. Αν διαπιστωθεί αλλαγή της, τότε ο DUC στέλνει άλλο ένα request που αναφέρει πως θα πρέπει να γίνει η αλλαγή της διεύθυνσης και στον κατάλογο του DNS. (αυτή είναι η γενική ιδέα)

The most exchanged data by the client program through the internet is the question of the current IP address our ISP provided to us. Every time DUC wants to find our IP, it sends a request to NoIP's server. The server checks which is the source IP of the request and returns it to DUC. If DUC finds a different IP than the one of the previous request, it sends another request for the DNS table updating (That is the general idea)

Επειδή η αλλαγή της διεύθυνσης συμβαίνει σε αραιά χρονικά διαστήματα (ανά μερικές ημέρες), η περισσότερη επικοινωνία που συμβαίνει (το ερώτημα της τρέχουσας IP διεύθυνσης) είναι άσκοπη. Ταυτόχρονα, σκοπός μας είναι να μπορέσουμε να υποβάλουμε ερώτημα για τη διεύθυνση IP τόσο συχνά ώστε να μην υπάρχει μεγάλο χρονικό διάστημα όπου ο DNS περιέχει παλαιά διεύθυνση (να είναι ασυγχρόνιστος).

Since an IP change happens in very big intervals (several days), the most communication traffic happens (the query of tha current IP address) is pointless. At the same time, our goal is to send an IP address query as often as possible, for the time the DNS contains our old address (not be synchronized) be as small as it can be.

Ο πιο απλός τρόπος είναι να μην υποβάλλεται το ερώτημα στον server της NoIP, αλλά στο router μας. Πολλά router έχουν ενεργοποιημένο telnet server, έτσι ώστε να μπορούμε να συνδεθούμε με αυτό το πρωτόκολλο και να εκτελούμε εντολές. Μια άλλη εναλλακτική υπάρχει αν το router που διαθέτουμε τρέχει ssh server, οπότε μπαίνουμε με ssh στο router και πάλι μπορούμε να εκτελέσουμε εντολές. Κάποια, βέβαια, routers δεν έχουν τίποτα από τα δυο (π.χ. κάτι oxygen)... Εκεί θα πρέπει να κάνουμε ερώτημα μέσω https (συνήθως).

The simplest way is to send the IP address query, not to NoIP's server but to our router. Many routers provide a telnet server, thus, we can connect to it using that protocol and execute commands. Another alternative exists is our router runs a ssh server, so we connect to it using ssh and again we can execute commands. Well, there is also the possibility for some routers not to provide any of the above (ie. some oxygen routers)... We can send them queries using https protocol (usually).

Επειδή δεν είναι σταθερός ο τρόπος με τον οποίο υποβάλλουμε ερώτημα για την IP στο router, σε αυτό το άρθρο θα παρουσιαστεί ένα script που είναι για χρήση σε πρωτόκολλο telnet που είναι και το πιο συχνά εμφανιζόμενο. Συγκεκριμένα έχει δοκιμαστεί σε τρία διαφορετικά routers. Ένα ZTE (που δίνει ο ΟΤΕ), ένα TP-Link και ένα AirTies. Φυσικά, με διαφορετικό configuration. Τα δύο από τα τρία εκτελούν κανονικές εντολές Linux, ενώ το TP-Link έχει δικές του εντολές.

Since the way we question our router for our IP address is not by default the same to all routers, in this article we present a script that uses telnet protocol, which is the most applicable. We have tested it in three different routers, a ZTE (the Greek Telecomunications Company provides), a TP-Link and an AirTies. Of course, we used different configuration. Two of these execute normal Linux commands, while the TP-Link has its own.

Αρχικά, ας δημιουργήσουμε τις συνθήκες για να κάτσουν τα script. Πρώτο βήμα είναι να φτιαχτεί ο κατάλογος που θα φιλοξενήσει τα scripts:

First, lets create the space our scripts will sit in. The first step is to create a directory that will host the scripts:

pi@raspberrypi:~ > sudo mkdir /usr/scripts
pi@raspberrypi:~ > cd /usr/scripts
pi@raspberrypi:/usr/scripts > 

Ας δούμε το script που υποβάλλει ερώτημα στο router για την IP. Το script είναι γραμμένο σε python. Μιας και δεν είμαι γνώστης της python, δεν περιμένω ότι το script αυτό είναι το τελειότερο του κόσμου (λέμε τώρα!). Είναι το πρώτο script που γράφω στη συγκεκριμένη γλώσσα προγραμματισμού οπότε κάποιος έμπειρος python προγραμματιστής πολύ πιθανό να βρει κάποιες ατέλειες. Επίσης, είναι μια πρώτη έκδοση. Σκοπεύω στο μέλλον (κοντινό) να του μπαλώσω μια "τρύπα" που έχει. Αλλά για την ώρα κάνει τη δουλειά του. Μπορείτε να το κάνετε Copy/Paste στον αγαπημένο σας editor από εδώ:

Lets see the script that questions the router for our current IP address. This script is written in python. Since I'm not a python programmer, I don't expect this script to be the most perfect one all over the world (well... matter of speaking!). It is my first python script so any experiences python programmer will find some defects. Also, this is a first version. In the future (near future) I intend to patch a "whole" in there. But for now it does what it promises. You can Copy/Paste it in your favourite editor from here:

#!/usr/bin/python
# THE SOFTWARE IS LICENSED UNDER GPL2 GENERAL PUBLIC LICENSE v2.
# IN ORDER TO OBTAIN A COPY OF THIS LICENSE PLEASE VISIT THE FOLLOWING
# ADDRESS:
# http://www.gnu.org/licenses/gpl-2.0.html

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#First import the necessary python libraries
import sys
import os
import telnetlib

#Setup the default values, before using the configuration file
ConfFile = "/etc/GetInetIP.conf"
RouterIP = "192.168.1.1"
UserName = "admin"
Password = "admin"
NetComm = "ifconfig ppp0"
AddrPrefix = "inet "
ExpTime = 0.0001

#If the user has entered a CLI argument, use it as the configuration file to be used
InArgs = len(sys.argv)
if InArgs > 2:
        sys.stderr.write("ERROR: Only one input argument expexted!\n")
        sys.stderr.write("Usage: GetInetIP [configuration_filename]\n");
        exit(1)
elif InArgs == 2:
        ConfFile = sys.argv[1]
        #Need to check if the user specified filename exists. If not => Error
        if not(os.path.exists(ConfFile)):
                sys.stderr.write("ERROR: Configuration file" + ConfFile + "not found\n")
                exit(2)

#Check for the existance of the configuration file

#Time to import the configuration file's values. If the user specified a configuration file
# then it really exists. But if not, we must try to load the configuration file from
# the default path. If this file doesnot exist, then we ave to use our hardcoded values
#NOTE:The execfile command should be changed for security reasons... A more secure approach
# is to parse the configuration file, and not execute it... (no time to fixit right now)
if os.path.exists(ConfFile):
        execfile(ConfFile)

#Connect to the specified router using telnet protocol
Conn = ""
try:
        Conn = telnetlib.Telnet(RouterIP)
except:
        sys.stderr.write("ERROR: Cannot communicate with" + RouterIP +"\n")
        exit(3)

#Send the login credentials
RespStr = "First"
FailCount = 3
while (RespStr != "") and (FailCount > 0):
        RespStr = Conn.read_until("\n",ExpTime)
        LoginFlag = RespStr.find("login:")
        if LoginFlag >= 0:
                Conn.write(UserName + "\n")
                RespStr = Conn.read_until("\n",ExpTime)
        PassFlag = RespStr.find("Password:")
        if PassFlag >= 0:
                Conn.write(Password + "\n")
                RespStr = Conn.read_until("\n",ExpTime)
                FailCount -= 1

if FailCount == 0:
        sys.stderr.write("ERROR: Credentials failed 3 times\n")
        exit(4)

#Now the telnet awaits commands! Issue the command that announces the IP needed
Conn.write(NetComm +"\n")
RespStr = Conn.read_until("\n",ExpTime)
InetFlag = False
while (RespStr != "") and not(InetFlag):
        InetStrt = RespStr.find(AddrPrefix)
        if InetStrt >= 0:
                InetFlag = True
                InetStrt += len(AddrPrefix)
                InetEnd = RespStr.find(" ",InetStrt)
        else:
                RespStr = Conn.read_until("\n",ExpTime)
Conn.write("exit\n")
DummyStr = Conn.read_all()
Conn.close()
if not(InetFlag):
        sys.stderr.write("ERROR: IP Address not found\n")
        exit(5)
OutStr = RespStr[InetStrt:InetEnd]
print(OutStr.strip())
exit(0)

Αυτό το script το σώζουμε με το όνομα GetInetIP.py μέσα στον κατάλογο που φτιάξαμε. Για να λειτουργήσει χρειάζεται και ένα configuration αρχείο μέσα στον κατάλογο /etc. Προσοχή χρειάζεται στο ότι στο configuration αρχείο βρίσκονται στοιχεία που δεν πρέπει να φτάσουν στα μάτια τρίτων! Κοινώς, το password του router... Το αρχείο θα πρέπει να ονομάζεται GetInetIP.conf:

We save it with the name GetInetIP.py under the directory we created earlier. For the script to function properly it needs a configuration file in /etc directory. Caution is needed as in this configuration file some strings are for your eyes only! More specifically, your router's password... The file must be named GetInetIP.conf:

Configuration για router TP-Link

Configuration for TP-Link router

RouterIP = "192.168.1.1"
Password = "MyCrazyPassword"
NetComm = "show wan status"
AddrPrefix = "Ip = "
ExpTime = 0.07

Ας δούμε λίγο τα περιεχόμενα του configuration αρχείου:

Lets see the bones of this configuration file:

  • RouterIP: Δηλώνει τη διεύθυνση IP που έχει το router μαςSpecifies the router's IP address
  • UserName: Το όνομα χρήστη για το router. Αν δεν δηλώνεται εδώ χρησιμοποιείται η default τιμή που είναι το admin. Κάποια από τα routers δε ζητάνε το username. Σε αυτή την περίπτωση το script το καταλαβαίνει και δεν το στέλνει.The username of the router's administrator. If it not specified it takes the default value which is "admin". Some routers do not ask for a username. In that case the script is smart enough to understand it and it does not send a username at all.
  • Password: Το password που χρειαζόμαστε για να κάνουμε login στο routerThe password we need to login to router
  • NetComm: Η εντολή που εκτελούμε, όταν κάνουμε telnet στο router που μας δείχνει τη διεύθυνση IP που έχει στο WAN. Για το TP-Link είναι show wan status, ενώ για ένα router που τρέχει busybox ή γενικά εκτελεί εντολές Linux είναι κάτι του στυλ ifconfig ppp0The command we need to execute, using telnet, that announces the IP address of the WAN. For TP-Link it is show wan status, while for a router that runs busybox or executes Linux commands it is something like ifconfig ppp0
  • AddrPrefix: Όποια και αν είναι η εντολή που μας δίνει την επιθυμητή πληροφορία, δεν δίνει απλά ένα ξερό νούμερο, αλλά ολόκληρο κείμενο. Εδώ περιγράφεται τι περιμένει το script για να βρει ακριβώς πριν τη διεύθυνση IP που μας ενδιαφέρει. Αμέσως μετά από αυτό το κείμενο αναφέρεται η πληροφορία μας.Whichever the command is to get our IP address, it does not return only this number, but a whole text containing the desired information. This value describes what the script expects just before the IP address we need to filter. Just after that text placed in this variable the IP address appears.
  • ExpTime: Είναι ο χρόνος μέσα στον οποίο αν το router δεν στείλει κάποιο χαρακτήρα, θεωρείται πώς δεν έχει κάτι άλλο να στείλει. Προσοχή, σε άλλα router είναι μικρότερος και σε άλλα μεγαλύτερος. Γενικά, ο μεγάλος χρόνος κάνει για όλα τα router, αλλά καθυστερεί την εξέλιξη του script.This is the time that the script expects the router to sent a character. If there is no character during this time interval, the script assumes there is nothing more coming from the router as an answer. Be careful, at some routers this time is small while at others it is larger. In general, a bigger value is suitable for all routers but it slows down the performance of the script.

Αν μπούμε χειροκίνητα σε ένα TP-Link router και δώσουμε την εντολή show wan status τότε θα δούμε τα ακόλουθα:

If we manually connect to a TP-Link router and execute the command show wan status then it will return the following:

eliaschr@orion:~> telnet router
Trying 192.168.1.1...
Connected to router.
Escape character is '^]'.

Password: *********************
Copyright (c) 2001 - 2011 TP-LINK TECHNOLOGIES CO., LTD.
TP-LINK> show wan status
PVC-0 
        Status = Up
PVC-1 
        Status = Up
PVC-2 
        Status = Up
PVC-3 
        Status = Up
PVC-4 
        Status = Up
        Ip = 94.71.120.43
PVC-5 
        Status = Up
PVC-6 
        Status = Up
PVC-7 
        Status = Down
TP-LINK> 

Βλέπουμε ότι ακριβώς πριν την IP που μας ενδιαφέρει βρίσκεται το Ip = . Αυτό είναι που βάζουμε στο AddrPrefix.

We can see that just before the IP address we need to read is Ip = . This is what we set AddrPrefix to.

Στην περίπτωση του ZTE και του AirTies ένα configuration αρχείο σαν αυτό που ακολουθεί κάνει τη δουλειά:

In case of a ZTE or an AirTies a configuration file like the following does the necessary job:

Configuration για router ZTE - AirTies - Linux style commands

Configuration for ZTE - AirTies routers - Linux style commands

RouterIP = "192.168.1.1"
Password = "MyCrazyPassword"
NetComm = "ifconfig ppp0"
AddrPrefix = "inet addr:"
ExpTime = 0.05

Φυσικά, όποιο και να είναι το configuration που θα επιλέξετε, το μόνο σίγουρο είναι πως δεν πρέπει να το διαβάζει κανένας, παρά μόνο ο root!:

Of course, whichever is the configuration you choose, it is mandatory to be accessible by no one, except root!:

pi@raspberrypi:/usr/scripts > chown root:root /etc/GetInetIP.conf
pi@raspberrypi:/usr/scripts > chmod 0600 /etc/GetInetIP.conf
pi@raspberrypi:/usr/scripts > 

Dynamic Updater Client script

Ωραία! Αφού φτιάξαμε το script που μας διαβάζει την IP από το router μας, μένει να φτιάξουμε και το script που θα κάνει τη δουλειά του NoIP DUC. Δημιουργήστε το αρχείο IP-Updater.sh στον κατάλογο /usr/scripts που φτιάξαμε πριν. Το αρχείο αυτό θα πρέπει να το κάνετε Copy/Paste από εδώ:

Great! After we created the script that reads our router's WAN IP address, we have to create a new script that will simulate NoIP DUC. Just create the file named IP-Updater.sh under the directory /usr/scripts as earlier. You can Copy/Paste the source of the script in question from here:

#!/bin/bash
# THE SOFTWARE IS LICENSED UNDER GPL2 GENERAL PUBLIC LICENSE v2.
# IN ORDER TO OBTAIN A COPY OF THIS LICENSE PLEASE VISIT THE FOLLOWING
# ADDRESS:
# http://www.gnu.org/licenses/gpl-2.0.html

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

# The script uses a configuration file that is called /etc/IP-Updater.conf
# Valid lines in the script are:
# NoIPUser=the_username_of_NoIP_login_account
# NoIPPass=the_password_of_the_account
# NoIPHost=the_host_to_which_the_IP_is_going_to_be_updated
# FindIPComm=/path/to/the_command_line_to_be_executed_to_get_the_IP
# FailIPDelay=Delay in seconds before retrying to find out the new
#       IP address, after a failure
# RepeatDelay=Delay in seconds before trying to refresh the IP after a
#       successful update
# FailDelay=Delay in seconds if there is a fatal error in NoIP. (Only if PreventExit=true)
# WGetDelay=Delay in seconds if there is a failure in wget to NoIP
# WGetLongFailDelay=Delay in seconds after Maximum number of failures reached
# WGetMaxFails=Maximum wget sequensial failures that make the daemon exit (unless
#       PreventExit=true
# MaxFailIPCnt=Maximum number of retries to fetch IP address from router
#       while it seems to have connection to the internet
# PreventExit={true/false} If true, then upon fatal error the script never ends
# SuccessCmd=Command to execute after a successful update to No-IP
# FailCmd=Command to execute after a failed NoIP update
# ExitCmd=Command to execute if the program must exit because of Fatal Error

# In ExitCmd, FailCmd and SuccessCmd you can use the following values as input:
#       $NoIPResp: if you want to include the responce from NoIP after the 
#               request of IP Address updating
#       $NewIP: the new IP that found and sent to NoIP
#       $CurrIP: the old IP that the system had before the update
#       $CurDate: the time that the execution of the IP update happened

PIDFILE=/var/run/IP-Updater.pid
PID=$BASHPID
LOGME="logger -ist 'NoIP-Updater'"
TEMPFILE="/tmp/CurrentIP"
TEMPWGET="/tmp/CurrentIP.wget"
CONFFILE="/etc/IP-Updater.conf"
USERAGENT="WGet from Raspberry Pi Linux/1.0 eliaschr@gmail.com"
NoIPUser=""
NoIPPass=""
NoIPHost=""
FindIPComm="echo 'ERROR: No router IP fetch program specified' >&2; exit 4;"
PreventExit=true
FailDelay=1800
MaxFailIPCnt=3
FailIPDelay=15
RepeatDelay=60
WGetDelay=5
WGetLongFailDelay=60
WGetMaxFails=10
SuccessCmd=""
FailCmd=""
ExitCmd=""
WGetErrMess[1]="Generic error code"
WGetErrMess[2]="Parse error"
WGetErrMess[3]="File I/O error"
WGetErrMess[4]="Network failure"
WGetErrMess[5]="SSL verification failure"
WGetErrMess[6]="Username/password authentication failure"
WGetErrMess[7]="Protocol errors"
WGetErrMess[8]="Server issued an error response"

CurrIP="x"

test -r $CONFFILE || ( echo "Failed to load the configuration file $CONFFILE..." >&2;
        exit 1 )

source $CONFFILE

touch $TEMPFILE
echo "" > $TEMPFILE

touch $PIDFILE
echo $PID > $PIDFILE

while true
do
        source $TEMPFILE
        FailCounter=$MaxFailIPCnt
        NextDelay=$RepeatDelay
        NewIP=`$FindIPComm`
        Status=$?

        while (( $Status != 0 ))
        do
                CurDate=`date +%T`
                $LOGME "$CurDate WARNING: Could not read the IP address"
                if (( $FailCounter == 0 ))
                then
                        $LOGME "Too many failures... Abording"
                        rm $PIDFILE
                        exit 2
                fi
                sleep $FailIPDelay
                PingStat=`ping -c1 www.no-ip.com > /dev/null; echo $?`
                if [[ "$PingStat" == "0" ]]
                then
                        NewIP=`$FindIPComm`
                        Status=$?
                        FailCounter=$((FailCounter -1))
                fi
        done

        if [[ "$CurrIP" != "$NewIP" ]]
        then
                CurDate=`date +%T`
                WGetStatus=`wget -qO $TEMPWGET -U "$USERAGENT" --user=$NoIPUser --password=$NoIPPass "http://dynupdate.no-ip.com/nic/update?hostname=${NoIPHost}&myip=$NewIP"; echo $?`
                NoIPResp=`cat $TEMPWGET`
                if (( $WGetStatus == 0 ))
                then
                        WGetFails=$WGetMaxFails
                        case ${NoIPResp/ */} in
                                "good")
                                        FailIPResult=0
                                        echo "CurrIP=$NewIP" > $TEMPFILE
                                        $LOGME "IP Address successfuly updated"
                                        ;;
                                "nochg")
                                        FailIPResult=1
                                        HostIPResp=`host $NoIPHost`
                                        if (( $? == 0 ))
                                        then
                                                HostIP=${HostIPResp/* /}
                                                if [[ "$HostIP" == "$NewIP" ]]
                                                then
                                                        FailIPResult=0
                                                        Comment="successfuly"
                                                        echo "CurrIP=$HostIP" > $TEMPFILE
                                                else
                                                        Comment="but it seems different than expected..."
                                                        NextDelay=$FailIPDelay
                                                fi
                                        else
                                                Comment="but could not resolve $NoIPHost"
                                                NextDelay=$FailIPDelay
                                        fi
                                        $LOGME "$CurDate WARNING: The IP in NoIP was updated by another process $Comment"
                                        ;;
                                "nohost")
                                        FailIPResult=1
                                        $LOGME "$CurDate ERROR: Hostname supplied does not exist under specified account"
                                        ;;
                                "badauth")
                                        FailIPResult=1
                                        $LOGME "$CurDate ERROR: Invalid username password combination"
                                        ;;
                                "badagent")
                                        FailIPResult=2
                                        $LOGME "$CurDate ERROR: Client disabled. Client should exit and not perform any more updates without user intervention"
                                        ;;
                                "\!donator")
                                        $LOGME "$CurDate ERROR: An update request was sent including a feature that is not available to that particular user"
                                        FailIPResult=1
                                        ;;
                                "abuse")
                                        $LOGME "$CurDate ERROR: Username is blocked due to abuse. Either for not following our update specifications or disabled due to violation of the No-IP terms of service"
                                        FailIPResult=1
                                        ;;
                                "911")
                                        $LOGME "$CurDate FATAL ERROR: NoIP.com error such as a database outage. Retry the update no sooner 30 minutes"
                                        FailIPResult=1
                                        NextDelay=1800
                                        ;;
                                *)
                                        $LOGME "$CurDate ERROR: Unknown responce from NoIP.com - $NoIPResp"
                                        FailIPResult=1
                                        ;;
                        esac

                        case $FailIPResult in
                                0)
                                        eval $SuccessCmd
                                        ;;
                                1)
                                        eval $FailCmd
                                        ;;
                                *)
                                        if $PreventExit
                                        then
                                                NextDelay=$FailDelay
                                                eval $FailCmd
                                        else
                                                eval $ExitCmd
                                                rm $PIDFILE
                                                exit 3
                                        fi
                                        ;;
                        esac
                else
                        $LOGME "$CurDate ERROR: Wget exited with error status $WGetStatus: ${WGetErrMess[$WGetStatus]}"
                        WGetFails=$((WGetFails -1))
                        if (( $WGetFails == 0 ))
                        then
                                WGetFails=1
                                NextDelay=$WGetLongFailDelay
                        else
                                NextDelay=$WGetDelay
                        fi
                fi
        fi

        sleep $NextDelay
done

Αυτό το script είναι γραμμένο σε bash shell. Και αυτό για να λειτουργήσει χρειάζεται το configuration αρχείο του, /etc/IP-Updater.conf. Ένα δείγμα του εν λόγω αρχείου φαίνεται ακολούθως:

The is a bash shell script. It also needs its configuration file, /etc/IP-Updater.conf. A sample of this file follows:

NoIPUser=noipusermail@myisp.gr
NoIPPass="MyUltraFancyPassword!"
NoIPHost=myhostname.no-ip.biz
FindIPComm="/usr/scripts/GetInetIP.py"
FailIPDelay=15
RepeatDelay=60
FailDelay=1800
MaxFailIPCnt=3
PreventExit=true
SuccessCmd="/usr/bin/ttytter -keyf=/etc/ttytter/Servertty -silent -status=\"\`date\` IP Updated successfully. NoIP Response is: \$NoIPResp\""
FailCmd="/usr/bin/ttytter  -keyf=/etc/ttytter/Servertty -silent -status=\"\`date\` IP Update failed. NoIP Response is: \$NoIPResp\""
ExitCmd="/usr/bin/ttytter  -keyf=/etc/ttytter/Servertty -silent -status=\"\`date\` Fatal Error during IP Update. NoIP response is: \$NoIPResp. Exiting...\""

Ας δουμε μια λίστα με πιθανές παραμέτρους του αρχείου:

Lets see a list of the possible parameters that can be specified in this file:

  • NoIPUser: Δηλώνει τη διεύθυνση mail του λογαριασμού του χρήστη που έχουμε φτιάξει στο NoIPSpecifies the e-mail address of the NoIP user's account we have created
  • NoIPPass: Το password που έχουμε στο NoIP λογαριασμόThe password for this account
  • NoIPHost: Το όνομα του domain που έχουμε καταχωρήσειThe domain name we own (or the one from the default that NoIP provides).
  • FindIPComm: Δηλώνεται το script που όταν τρέξει μας δίνει τη διεύθυνση IP του router. Κοινώς, το script που φτιάξαμε πριν σε pythonThe script name (command) that returns the IP address from our router. It is the script in python, we created earlier
  • FailIPDelay: Όταν δεν καταφέρει να διαβάσει την IP από το router, όπως σε περίπτωση που το router δεν έχει πάρει ακόμα IP μετά από διακοπή ρεύματος, ή το router είναι σβηστό, το script περιμένει όσα δευτερόλεπτα ορίζονται σε αυτή την παράμετρο, πριν ξαναπροσπαθήσειWhen the script fails to read the WAN IP from the router, as in case the router still waits for the ISP to send its IP after a power failure, or even if the router is powered off, the script sleeps for as many seconds as specified in this parameter before retrying
  • RepeatDelay: Όταν διαβάσει σωστά μια IP διεύθυνση, δηλώνει σε πόσο χρόνο θα ξαναπροσπαθήσει να δει αν υπάρχει αλλαγή τηςWhen the script fetches the IP address correctly, this parameter defines how much time it will wait until it checks again for an IP change
  • FailDelay: Όταν υπάρξει πρόβλημα στην ενημέρωση της καινούργιας IP, όπως σε περίπτωση που το NoIP επιστρέψει "911", το script περιμένει όσο χρόνο δηλώνεται εδώ σε δευτερόλεπτα πριν ξαναπροσπαθήσει την ενημέρωση του NoIP DNSWhen there is a failure during NoIP address update request, as in case NoIP server answers with "911", the script waits for such time as described in here, in seconds before retrying
  • MaxFailIPCnt: Ο μέγιστος αριθμός προσπαθειών στις οποίες δε θα μπορέσει να διαβάσει την IP διεύθυνση από το router, ενώ πιστοποιείται πως υπάρχει σύνδεση με το internet. Αυτή η κατάσταση κανονικά δεν πρέπει να υπάρξει ποτέ.The maximum number of retries that will fail to read the IP address from the router, while there is certified internet connection. Normally, this state will never be reached.
  • PreventExit:true ήor false. Αν είναι true τότε το script δε σταματάει ποτέ, ούτε σε περίπτωση λάθους όπως π.χ. username/password στο NoIPIf it is true the script never ends, not even in case of a failure like ie. wrong NoIP username/password
  • SuccessCmd: Εντολή που θα εκτελείται όταν έχουμε μια σωστή απάντηση από το NoIP όσον αφορά την ανανέωση της IP μας. Στο παράδειγμα φαίνεται να τρέχει το ttytter με τέτοιο τρόπο ώστε να μπορεί να στέλνει tweet την κατάστασή του. Δώστε βάση στον τρόπο με τον οποίο δηλώνονται μεταβλητές και εσωτερικές εκτελέσεις εντολών, όπως η dateCommand to be executed when there is a correct answer from NoIP for our IP address updating to DNS tables. In this example ttytter is executed in a way to tweet us the DNS status. Pay attention to the way the variables are specified in this command and interna command execution, like date
  • FailCmd: Το ίδιο, αλλά για την περίπτωση όπου υπάρξει απάντηση σφάλματος από το NoIPSame thing for the case of a NoIP answer for failure
  • ExitCmd: Ομοίως για την περίπτωση όπου υπάρξει τέτοιο σφάλμα όπου θα πρέπει το script να τερματιστείAnd again same thing in case the failure is severe and the script must be terminated
  • WGetDelay: Το script χρησιμοποιεί τη wget για να στείλει το request στο NoIP server. Σε περίπτωση που υπάρξει σφάλμα περιμένει όσο χρόνο του ορίζει αυτή η μεταβλητήThis script uses wget to send a request to NoIP server. In case of request failure it wait for as long as this parameter specifies
  • WGetMaxFails: Όταν υπάρξουν τόσα σφάλματα στη σειρά από τη wget όσα ορίζονται σε αυτή την παράμετρο, τότε ο χρόνος αναμονής μέχρι το επόμενο wget που θα επιχειρηθεί ορίζεται από την WGetLongFailDelayWhen there are as many wget failures as this parameter specifies, then the delay until any further wget request will be as WGetLongFailDelay specifies.
  • WGetLongFailDelay: Μετά από WGetMaxFails αποτυχίες της wget ο χρόνος που περιμένει πριν ξαναδοκιμάσει να στείλει request ορίζεται από αυτή την παράμετροAfter WGetMaxFails wget failures, the delay interval till next retry is specified by this parameter

Το script μας δίνει τη δυνατότητα να εκτελέσουμε κάποιες εντολές, ανάλογα με το αν ήταν επιτυχής η αλλαγή της IP, αν υπήρξε κάποιο σφάλμα, ή αν υπήρξε μια ανεπίτρεπτη κατάσταση που οδηγεί το script σε τερματισμό. Οι εντολές αυτές ορίζονται στις παραμέτρους SuccessCmd, FailCmd και ExitCmd. Σε αυτές τις εντολές, μπορεί να θέλουμε να χρησιμοποιήσουμε κάποιες πληροφορίες από το script. Οι δυνατές περιπτώσεις είναι οι:

The script provides us the ability to execute some commands depending on the case of success or failure of the IP update request, or even if there was a severe error that forced the script to terminate. The commands in question are specified in SuccessCmd, FailCmd and ExitCmd parameters. In these commands we may need to use some information coming from the script. The possible script variables are:

  • $NoIPResp: Περιέχει την απάντηση από τον server της NoIPContains the answer of the NoIP server
  • $NewIP: Περιέχει την καινούργια IP διεύθυνσηContains the new IP address
  • $CurrIP: Περιέχει την παλιά IP διεύθυνσηContains the old IP address
  • $CurDate: Περιέχει την ώρα που ανιχνεύτηκε η αλλαγή της IPContains the time value the IP change was detected

Και φυσικά, μιας και σε αυτό το αρχείο περιέχονται ευαίσθητες πληροφορίες, θα πρέπει να μπορεί να το διαβάσει μόνο ο root:

Well, of course in this file there are also sensitive information that only root should be able to read:

pi@raspberrypi:/usr/scripts > chown root:root /etc/IP-Updater.conf
pi@raspberrypi:/usr/scripts > chmod 0600 /etc/IP-Updater.conf
pi@raspberrypi:/usr/scripts > 

Τέλος, μιας και αυτά τα δύο scripts είναι βασικά για τη λειτουργία του συστήματός μας, καλό είναι και αυτά να τα κάνουμε μη προσβάσιμα από τους χρήστες (εκτός του root):

Finally, since both scripts are mandatory for the functionality of our system, it is a good practice not to let any user access them (unless, of course root):

pi@raspberrypi:/usr/scripts > sudo chown -R root:root /usr/scripts
pi@raspberrypi:/usr/scripts > sudo chmod -R 0700 /usr/scripts
pi@raspberrypi:/usr/scripts > 

Μετατροπή του καινούργιου client σε υπηρεσία

Conversion of the new client to a system service

Το τελικό στάδιο είναι να εκτελείται το script που φτιάξαμε ως υπηρεσία του συστήματος. Κάποιος θα μπορούσε πολύ απλά να το τρέξει μέσα από τον cron. Αυτό όμως δεν θεωρείται και τόσο καλή ιδέα. Είναι σαφώς καλύτερα να λειτουργεί όπως όλες οι υπηρεσίες του συστήματος, να ενεργοποιείται και να απενεργοποιείται ανάλογα με το runlevel κ.λ.π. Για να το πετύχουμε αυτό θα πρέπει να φτιάξουμε ένα ακόμα script. Μια παρόμοια εργασία κάναμε και σε προηγούμενο άρθρο. Θα ακολουθήσουμε, λοιπόν, την ίδια τακτική.

The final stage is to let the script we created run as a system service. Somebody would let it start through cron. But this is not considered a good practice. It is far better to let it act as any other system service, start or stop depending on the runlevel of the system, etc. To reach our goal we must create another one script. A similar process we followed in an earlier article. We will follow the same tactics.

Κάντε Copy/Paste τον ακόλουθο κώδικα στον αγαπημένο σας editor:

Again, you can Copy/Paste the following source code in your favourite editor:

#! /bin/sh
### BEGIN INIT INFO
# Provides:          IP-Updater
# Required-Start:    $local_fs $syslog $network
# Required-Stop:     $local_fs $syslog $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: IP Updater for NoIP Dynamic DNS service
# Description:       Start IP Updater to check the IP that the ISP has given to router.
#       When the IP is changed, the updater informs NoIP and updates the chosen domain name
#       to point to the new IP.
### END INIT INFO

# Author: Elias Chrysocheris 
#

# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="IP Updating client service for NoIP (http://www.noip.com/)"
NAME=IP-Updater
DAEMON=/usr/scripts/IP-Updater.sh
SCRIPTNAME=/etc/init.d/$NAME
PIDFILE=/var/run/IP-Updater.pid

# Exit if the package is not installed
[ -e "$DAEMON" ] || { echo "Cannot find IP-Updater executable in $DAEMON. Perhaps it is not installed...";
        if [ "$1" = "stop" ]; then exit 0;
        else exit 5; fi; }

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{
        # Return
        #   0 if daemon has been started
        #   1 if daemon was already running
        #   2 if daemon could not be started
        start-stop-daemon --test --start --quiet --pidfile $PIDFILE --exec $DAEMON > /dev/null \
                || return 1
        start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON &
        RETVAL="$?"
        [ "$RETVAL" > 2 ] && return 2
        # Add code here, if necessary, that waits for the process to be ready
        # to handle requests from services started subsequently which depend
        # on this one.  As a last resort, sleep for some time.
}

#
# Function that stops the daemon/service
#
do_stop()
{
        # Return
        #   0 if daemon has been stopped
        #   1 if daemon was already stopped
        #   2 if daemon could not be stopped
        #   other if a failure occurred
        start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE
        RETVAL="$?"
        [ "$RETVAL" = 2 ] && return 2
        # Wait for children to finish too if this is a daemon that forks
        # and if the daemon is only ever run from this initscript.
        # If the above conditions are not satisfied then add some other code
        # that waits for the process to drop all resources that could be
        # needed by services started subsequently.  A last resort is to
        # sleep for some time.
        start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --pidfile $PIDFILE
        [ "$?" = 2 ] && return 2
        rm $PIDFILE
        return "$RETVAL"
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
        #
        # If the daemon can reload its configuration without
        # restarting (for example, when it is sent a SIGHUP),
        # then implement that here.
        #
        start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
        return 0
}

case "$1" in
  start)
        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
        do_start
        case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
        ;;
  stop)
        [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
        do_stop
        case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        esac
        ;;
  status)
        status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
        ;;
  #reload|force-reload)
        #
        # If do_reload() is not implemented then leave this commented out
        # and leave 'force-reload' as an alias for 'restart'.
        #
        #log_daemon_msg "Reloading $DESC" "$NAME"
        #do_reload
        #log_end_msg $?
        #;;
  restart|force-reload)
        #
        # If the "reload" option is implemented then remove the
        # 'force-reload' alias
        #
        log_daemon_msg "Restarting $DESC" "$NAME"
        do_stop
        case "$?" in
          0|1)
                do_start
                case "$?" in
                        0) log_end_msg 0 ;;
                        1) log_end_msg 1 ;; # Old process is still running
                        *) log_end_msg 1 ;; # Failed to start
                esac
                ;;
          *)
                # Failed to stop
                log_end_msg 1
                ;;
        esac
        ;;
  *)
        #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
        echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
        exit 3
        ;;
esac

Το script βασίστηκε για άλλη μια φορά στο κλασικό skeleton που υπάρχει στον κατάλογο /etc/init.d/. Εκεί θα το σώσουμε σαν root με το όνομα IP-Updater. Αν δεν έχουμε τη δυνατότητα να το κάνουμε απ' ευθείας, μπορούμε σαν χρήστες να το σώσουμε στον κατάλογό μας και στη συνέχεια να το αντιγράψουμε ως root στην κατάλληλη θέση. Στη συνέχεια αλλάζουμε τα δικαιώματα και το κάνουμε εκτελέσιμο και ενημερώνουμε το σύστημα για την καινούργια υπηρεσία:

This script is based once more in the clasical skeleton that lives under /etc/init.d/. There we eill save it as root user under the name IP-Updater. If you cannot do it straight forward, you can save it under your home directory and then you can copy it as root to the correct place. Then you can change its access rights making it executable and inform the system for the new service:

pi@raspberrypi:/usr/scripts > cd /etc/init.d/
pi@raspberrypi:/etc/init.d > sudo cp /home/pi/IP-Updater .
pi@raspberrypi:/etc/init.d > sudo chmod 0755 IP-Updater
pi@raspberrypi:/etc/init.d > sudo update-rc.d IP-Updater defaults
pi@raspberrypi:/etc/init.d > 

Μετά από αυτό μπορούμε να εκκινήσουμε την υπηρεσία μας. Όμως, για να δοκιμάσουμε ότι όλα βαίνουν καλώς, καλό είναι να δούμε αν ενεργοποιείται αυτόματα με μια επανεκκίνηση:

After that we can start the new service. But first we have to make sure everything is fine and the service starts automatically after a reboot:

pi@raspberrypi:/usr/scripts > sudo shutdown -r now
pi@raspberrypi:/etc/init.d > 

Αποτελέσματα

Conclusions

Εαν όλα έχουν πάει καλά, τότε μπορείτε να παρακολουθήσετε τα μηνύματα στο /var/log/messages και να δείτε τη λειτουργία του script. Αν προσέξατε, στο configuration αρχείο του IP-Updater, χρησιμοποιείται το ttytter που είναι ένας client για το twitter. Μέσω αυτού βλέπουμε on-line τη λειτουργία της αλλαγής διεύθυνσης

If everything is done correctly then you could see the information in /var/log/messages and watch the service in action. You must have noticed, in the IP-Updater configuration file, ttytter is used which is a command line twitter client. Using that we can observe on-line the function of IP updating

Αυτό φυσικά προϋποθέτει να έχετε στήσει το ttytter και να το έχετε ρυθμίσει.

For this you are supposed to have ttytter installed and configured.

Έπειτα από αρκετό καιρό που λειτουργεί η υπηρεσία του NoIP στο Raspberry Pi δεν έχω πετύχει κατάσταση που να μη μπορώ να έχω πρόσβαση μέσω του δικτύου, απομακρυσμένα. Η απόκριση του συστήματος είναι παραπάνω από ικανοποιητική.

Using NoIP service system in Raspberry Pi for enough time now, I never had that awkward moment of not having access to my system through the internet. The system's response is more than satisfactory.


Ηλίας Χρυσοχέρης

Elias Chrysocheris

Παρασκευή 31 Μαΐου 2013

Ubiquity UniFi Controller Software στο Raspberry PiUbiquity UniFi Controller Software on Raspberry Pi

Εισαγωγή

Introduction

Βασικά η ιστορία συνεχίζεται από προηγούμενο άρθρο που βρίσκεται σε αυτό το blog. Για να υπάρξει μια σύνδεση με τα προηγούμενα, θα γίνει μια γενική περιγραφή του προβλήματος. Στη συνέχεια θα δούμε λίγα πράγματα για ένα εργαλείο που θα χρησιμοποιήσουμε (το Raspberry Pi) για τη λύση του προβλήματος και θα προχωρήσουμε στον τρόπο που ακολουθήθηκε για να επιτευχθεί το επιθυμητό αποτέλεσμα.

The story continues from an earlier post posted in the current blog. For clarity and connection to the previously mentioned information, there will be a general description of the problem. Then we will get to know the tool we use in this article (Raspberry Pi) for the solution of the problem and we will present the way we followed to reach our goal.

Επιγραμματικά ακολουθούν:

Briefly:

Το βασικό πρόβλημα

The Problem

Το βασικό κομμάτι που μας ενδιαφέρει εδώ, είναι το στήσιμο ενός δικτύου ξενοδοχείου. Αυτό, με τη σειρά του, συνεπάγεται όλο το καλό πακέτο του ελέγχου σύνδεσης των πελατών, ποσού διακίνησης δεδομένων κ.λ.π. Αυτό το επιτυγχάνουν επαρκώς και με το παραπάνω τα Access Points της Ubiquity. Η χρήση ενός UniFi Outdoor Access Point λύνει όλα τα προβλήματα δικτύωσης. Το μόνο μειονέκτημα (και αυτό που μας απασχολεί στο παρόν άρθρο) είναι πως θα πρέπει να υπάρχει ένα μηχάνημα που να τρέχει το software της εταιρίας για τον έλεγχο και τη διαχείριση του δικτύου. Αυτό με τη σειρά του συνεπάγεται κατανάλωση ενέργειας για PC, θόρυβος από τα ανεμιστηράκια του, απαραίτητη χρήση UPS που να αντέχει σε μεγάλες διακοπές ρεύματος, license του λειτουργικού του συστήματος αν πρόκειται για μηχάνημα που τρέχει Bugindows, συχνές επανεκκινήσεις λόγω των προβλημάρων του αναφερόμενου λειτουργικού κ.λ.π. Ειδικα τα δύο τελευταία προβλήματα (που είναι και τα πιο σημαντικά) λύθηκαν με την εγκατάσταση λειτουργικού Linux και συγκεκριμένα της διανομής openSUSE, όπως φαίνεται και σε άλλο άρθρο του ίδιου blog.

The basic part in question at this point is a network setup for a hotel. This means the whole packet of services for controlling client access, bandwidth limiting per client, data quota etc. For Ubiquity's Access Points this is only part of their capabilities. Usage of a UniFi Outdoor Access Point is the solution for all our networking problems. The only drawback (and what is covered in this article) is the necessity of a computer running the controller software for all the network monitoring and managing, 24 hours a day. And this, in turn, leads to much energy consumption from a PC, noise from its fans, the necessity of UPS usage that is able to keep the system up during long duration power failures, license for its operating system if it runs Bugindows, probably frequently reboots because of this (non) operating system and many more... Especially the two last problems we presented (which are the most important) were solved by installing a Linux distribution; more specifically openSUSE, as presented in a previous article in this blog.

Η λύση των υπολοίπων προβλημάτων διερευνήθηκε περισσότερο για να βρει ο γράφων δουλειά να κάνει (!!! Τι πρωτότυπο :)). Δεν είναι κάτι άλλο από το πασίγνωστο, πλέον στο χώρο των gadgetάκιδων, Raspberry Pi.

The research for solutions to the other problems started just for the author to kill some of his spear time (!!! How rare :)). The research led to, famous in the gadget lovers' cycles, Raspberry Pi.

Raspberry Pi ως server...

Raspberry Pi as a server...

Το Raspberry Pi είναι ένας υπολογιστής, όπως ακριβώς κι ένα κινητό. Η διαφορά του είναι πως δεν έχει οθόνη. Τι διαθέτει αυτός ο υπολογιστής (βασικά χαρακτηριστικά):

Raspberry Pi is a small computer, just like a smartphone. Its difference is the lack of a screen. Part of its specifications are presented:

  • Επεξεργαστής: ARM στα 700MHz, με δυνατότητα Overclocking στο 1GHz
  • Processor: ARM running at 700MHz, with Overclocking capability up to 1GHz
  • Μνήμη: 256 MBytes η παλιά έκδοση (Α), 512 MBytes η έκδοση Β
  • Memory: 256 MBytes at the old version (Α), 512 MBytes at its newer version, Β
  • Ethernet: 10/100 Mbit
  • Video out: Δε μας ενδιαφέρει. Server θέλουμε να το κάνουμε, αλλά ως άχρηστη πληροφορία της ημέρας διαθέτει έξοδο HDMI και TVWe don't care. We want to use it as a server, but as useless information of the day it has HDMI and Composite Video outputs
  • USB: 2 πόρτεςports
  • Boot: από κάρτα μνήμηςfrom an SD Card
  • Τροφοδοσία: 5V με μικρή κατανάλωση ρεύματος (μέγιστη στα 700mA στην έκδοση Β)
  • Power: 5V having small power consumption (maximum 700mA on version Β)

Αυτά τα χαρακτηριστικά το κάνουν ιδανικό για χρήση ως server. Δίνουν, επίσης, τη δυνατότητα να μπορέσει να τροφοδοτηθεί, αργότερα, από ένα σύστημα UPS που να παράγει τα 5V που χρειάζονται απ' ευθείας από τη μπαταρία του. Κατά συνέπεια μια διακοπή της ΔΕΗ για... πολλές ώρες δεν θα το ενοχλήσει :)

These specifications make this thing ideal for making a server. They also give it the ability to be, later, powered by a small UPS system that supplies 5V DC straight from a battery, without the need of inverters and 220V AC. So, a power failure because of the power company for... looong duration won't bother the system :)

Άλλο ένα καλό του εν λόγω gadget είναι πως πάρα πολλές διανομές Linux έχουν στηθεί για το Raspberry Pi· ακόμα και FreeBSD μπορούμε να βρούμε (αν και κανονικά αυτό δεν πρέπει να μας κάνει εντύπωση!). Μιας και την τελευταία φορά που έστησα το σύστημα του UniFi Controller ήταν επάνω σε openSUSE, δοκίμασα την εν λόγω διανομή και στο Raspberry Pi. Τα αποτελέσματα ήταν θαυμάσια. Το μόνο περίεργο ήταν η εγκατάσταση της Java, αλλά δεν ήταν κάτι που να αξίζει αναφοράς.

Another plus of this gadget is that there are so many Linux distributions running on Raspberry Pi right now; you can even find FreeBSD (though this should not impress us!). Since my last time I set up UniFi Controller was in an openSUSE Linux, I also tried it in Raspberry Pi. The results were marvellous. The only weird thing was the Java installation, but nothing worth mentioning here.

Κάτι που με "έτρωγε" ήταν πως αν κάποιος πάρει ένα Raspberry Pi και θελήσει να ασχοληθεί με τη χρήση του σε δίκτυο, όπως και αυτό που ήταν το έναυσμα για αυτή την ιστορία, τότε αμφιβάλλω αν θα ασχοληθεί με το να βάλει openSUSE· σίγουρα θα ασχοληθεί με το "έτοιμο" Raspbian που είναι βασισμένο επάνω στη διανομή Debian. Οπότε, για να μπορέσω να συμβάλλω και σε αυτό τον τομέα θα έπρεπε να δοκιμάσω αυτή τη διανομή για τις "ταρζανιές".

Something that really made me worried was that if someone gets a Raspberry Pi and wants to use it like what described in this article then I doubt he/she will install openSUSE; I bet on the default Raspbian operating system that is based on Debian. So, for me to be a contributor at this part I should use this distribution for all the play.

Το Στήσιμο

The Setup

Το στήσιμο του συστήματος δεν είναι καθόλου δύσκολο. Μπορεί κάποιος να κατεβάσει το κατάλληλο image και να το γράψει σε μια κάρτα μνήμης SD, ή να χρησιμοποιήσει το BerryBoot. Η δεύτερη επιλογή απλά θα προσθέσει μερικά δευτερόλεπτα στο bootάρισμα του συστήματος, αλλά αν κάποιος θέλει να "παίξει" με το Raspberry τότε είναι μια καλή λύση.

The system's setup is not difficult at all. Anyone can download the correct OS image that suits his/her needs and write it in an SD Memory Card. Alternatively BerryBoot can be used. The latter will just add some seconds during boot up of the system, but if somebody wants to "play" with Raspberry then it is a marvellous choice.

Η κάρτα που χρησιμοποιήθηκε στο στήσιμό μας είναι μια 8GB SD Class 10. Δίνει αρκετό χώρο για "παιχνίδια", ενώ είναι αρκετά γρήγορη για ένα ικανοποιητικό χρόνο εκκίνησης. Εκεί εγκαταστάθηκε το Raspbian, ρυθμίστηκε για λίγο overclocking (800 MHz) και έγινε και expand το partition που περιέχει το λειτουργικό. Αυτά, επειδή δεν υπήρχε πληκτρολόγιο στο Raspberry, έγινε μέσω ssh, εκτελώντας από εκεί το raspi-config.

The memory card used here is a 8GB SD Class 10. It gives much space to play, while at the same time is very fast for a short boot time. There was Raspbian installed, configured for some overclocking (800 MHz) and the partition containing the operating system was expanded. Because of lack of a keyboard connected to Raspberry, all these were done through ssh, running raspi-config.

Σε γενικές γραμμές η εγκατάσταση του συστήματος δε νομίζω πως χρειάζεται παρουσίαση. Όλα υπάρχουν στο Internet και είναι αρκετά κατανοητά για κάποιον ο οποίος αποφασίζει να ασχοληθεί με το Raspberry. Έτσι, οι λεπτομέρειες της εγκατάστασης λειτουργικού και ενεργοποίησης του συστήματος, καθώς επίσης και της αναβάθμισης του λογισμικού δεν περιγράφονται.

In general, the system installation was smooth and it doesn't worth mentioning. Every tip and information on that lies in the Internet and are crystal clear for anybody who wishes to use Raspberry Pi. So, all these installation details as well as those for updating the operating system are not presented.

Η αρχική εγκατάσταση περιέχει ένα χρήστη με το όνομα pi, ο οποίος ανήκει στο group pi, έχει password το raspberry, ενώ το όνομα του συστήματος στο δίκτυο είναι raspberrypi. Φυσικά, σε όλα αυτά έγιναν αλλαγές, οπότε ο χρήστης του συστήματος ονομάστηκε elias (λέμε τώρα!), το αρχικό group του χρήστη έχει το ίδιο όνομα, ενώ το δικτυακό όνομα του συστήματος έγινε unificontroll και διάφορα άλλα μικροσεταρίσματα.

The default installation has a user named pi, who belongs to pi group, identified by raspberry as password and the network name of the system is raspberrypi. Of course, changes have been made to all of these settings, so the user name now becomes elias (well, for the clarity of this article!), the initial user's group has the same name and the network name becomes unificontroll. There were also some minor alterations on the setup not worth mentioning.

Προεργασία

Groundwork

1. Εγκατάσταση Java
1. Java Installation

Για να λειτουργήσει το UniFi Controller χρειάζεται τη βάση δεδομένων mongodb και τη γλώσσα Java να είναι εγκαταστημένα στο σύστημα. Για τη Java δεν υπάρχει κάποιο πρόβλημα, μιας και είναι έτοιμη σε πακέτο .deb για το Raspbian. Αρκεί ένα

For UniFi Controller to be able to operate, it needs mongodb database and Java programming language installed in the target system. Java is no problem since there is already a .deb package for Raspbian. Just execute:

elias@unificontrol:~ > sudo apt-get install openjdk-7-jdk
[sudo] password for elias:
.
.
.

2. Εγκατάσταση MongoDB
2. MongoDB Installation

Το περίεργο της υπόθεσης είναι πως δεν υπάρχει πακέτο για MongoDB (τουλάχιστον μέχρι τη στιγμή που γράφεται το παρόν άρθρο). Κατά συνέπεια μπαίνουμε σε διαδικασίες compile κ.λ.π. Μετά από λίγο ψάξιμο βρέθηκε ένα πολύ καλό άρθρο για την εγκατάσταση της mongopi που είναι η μεταφορά της εν λόγω βάσης δεδομένων στο Raspberry. Το συγκεκριμένο άρθρο που βρέθηκε δίνει πληροφορίες για την εγκατάσταση ενός ολόκληρου συστήματος με πολλά Raspberries. Η περιγραφή που θα γίνει στο παρόν άρθρο είναι μόνο για την εγκατάσταση της MongoDB, ως το σημείο που χρειάζεται για να λειτουργήσει με το UniFi Controller.

Perhaps it is strange, but there is no package available for MongoDB (at least at the time of this writing). So, we have to proceed to other procedures like compiling etc. After some searching through the internet there was an article found for mongopi installation, which is the database in question patched for Raspberry. This article gives information for the whole process of a system with many Raspberries setup. The description in here, will be only for MongoDB installation, up to the necessary point to be functional and usable by UniFi Controller.

Ο κώδικας της mongopi είναι στο github. Για να γίνει η εγκατάσταση θα πρέπει να εγκατασταθούν πρώτα το git και κάτι ψιλά... Ξεκινάμε με την εγκατάσταση των απαραίτητων πακέτων γι' αυτή τη δουλειά:

mongopi code is available to download in github. For the total installation process to be complete, git and some other packages as well, must be installed... Lets start all these necessary installations:

elias@unificontrol:~ > sudo apt-get install git-core build-essential scons \
   libpcre++-dev xulrunner-dev libboost-dev \
   libboost-program-options-dev libboost-thread-dev \
   libboost-filesystem-dev
.
.
.

Στη συνέχεια κλωνοποιήσουμε το αποθετήριο με τα αρχεία της mongopi από το github:

OK. Now lets clone the mongopi repository from github:

elias@unificontrol:~ > git clone git://github.com/RickP/mongopi.git

Η συνέχεια θέλει υπομονή... Ώρα για compilation... Αυτό γίνεται με τη βοήθεια του εργαλείου scons και μπορεί να πάρει αρκετές ώρες (περίπου 4):

What follows needs patience... Time to compile the code... This is done using a tool named scons and it may take some hours (well, about 4):

elias@unificontrol:~ > cd mongopi
elias@unificontrol:~/mongopi > scons

Μετά από... λίγη ημέρα :) το compilation θα έχει τελειώσει. Συνέχεια έχει η εγκατάσταση. Αυτή θα χρειαστεί μόνο... 3 ώρες!...

After some... day passes :) the compilation process will be over. Installation follows. This will take only about... 3 hours!...

elias@unificontrol:~/mongopi > sudo scons --prefix=/opt/mongo install

Αυτή η εντολή θα εγκαταστήσει τη mongopi στον κατάλογο /opt/mongo. Φυσικά η όλη διαδικασία έπιασε και υπερβολικό χώρο στην κάρτα μνήμης (περίπου 2GB) οπότε καλό είναι να σβήσετε τον κατάλογο που περιέχει τον πηγαίο κώδικα:

That command will install mongopi in /opt/mongo directory. Naturally, the whole compilation/installation process allocated a huge space in the memory card (something around 2GB) so it is very good thing to delete the directory that contains the source code:

elias@unificontrol:~/mongopi > cd ..
elias@unificontrol:~ > sudo rm -rf mongopi
elias@unificontrol:~ > 

Καλό είναι να μπει στο PATH του συστήματος ο κατάλογος με τα εκτελέσιμα της MongoDB για να είναι εύκολη η διαχείριση των βάσεών της. Αυτό γίνεται απλά με την προσθήκη του στο αρχείο .bashrc της ακόλουθης γραμμής:

It is also a nice idea to insert into the PATH system variable the directory that contains all the executables of MongoDB, for easy access during databases administration. Just insert the following line in .bashrc file:

export PATH=$PATH:/opt/mongo/bin

Σε αυτό το σημείο η εγκατάσταση της MongoDB έχει γίνει. Αν χρειαστεί να τη χρησιμοποιήσετε και σε άλλες εφαρμογές, τότε πιθανό είναι να πρέπει να δημιουργήσετε και τον κατάλογο /data/db στο σύστημά σας. Αυτό στην περίπτωση του UniFi Controller δεν είναι απαραίτητο γιατί τη δικιά του βάση δεδομένων την κρατάει σε δικό του κατάλογο.

We reached the point that MongoDB is installed in the system. If you are going to also use it in other applications you possibly have to create /data/db directory, or mongo will complain. In the case of just using it only with UniFi Controller that step can be omitted, because it uses its own directory for the database contents.

Εγκατάσταση UniFi Controller

UniFi Controller Installation

Η εγκατάσταση του UniFi Controller δεν έχει κάποια δυσκολία. Σε γενικές γραμμές είναι ίδια με αυτή που έχει γίνει και σε προηγούμενο άρθρο σε άλλη έκδοση του λειτουργικού Linux

UniFi Controller installation is not difficult at all. It is about the same as described in a previous article in another Linux distribution.

Ξεκινάμε με το να δημιουργήσουμε ένα group με το όνομα unifid, όπου εκεί θα μπει και ο χρήστης που θα έχει τη δυνατότητα του custom portal για τους πελάτες του δικτύου. Μιας και ο μόνος χρήστης που υπάρχει αυτή τη στιγμή στο σύστημα είναι ο elias, αυτός είναι που θα προστεθεί και στο εν λόγω group.

Start from creating a user group named unifid, that will contain the user who will have the ability to create/alter the custom portal for the network clients. Since the only user existed in the system right now is elias, this user will be added into the group in question.

elias@unificontrol:~ > sudo addgroup unifid
Adding group `unifid' (GID 1003) ...
Done.
elias@unificontrol:~ > sudo adduser elias unifid
Adding user `elias' to group `unifid' ...
Adding user elias to group unifid
Done.

Για να δει το σύστημα την αλλαγή στα groups θα πρέπει να κάνουμε ένα logout και μετά ξανά login. Αυτό που φαίνεται στις ακόλουθες εντολές είναι η σύνδεση μέσω ssh από άλλον υπολογιστή:

For the system to read the new settings in you'll have to logout and relogin. What is presented in the following commands is a connection from another computer through ssh:

elias@unificontrol:~ > logout
Connection to 192.168.1.10 closed.
elias@otherpc:~> ssh 192.168.1.10
elias@192.168.1.10's password: 
Linux unificontrol 3.6.11+ #456 PREEMPT Mon May 20 17:42:15 BST 2013 armv6l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu May 30 11:43:24 2013 from 192.168.1.20
elias@unificontrol:~ > groups
elias adm dialout cdrom sudo audio video plugdev games users netdev input unifid
elias@unificontrol:~ > 

Το επόμενο βήμα είναι να κατεβάσουμε το .zip αρχείο του προγράμματος. Οι διαθέσιμες εκδόσεις είναι δύο:

The next step is to download the desirable .zip file of the program. The available versions (at the time of this writing) are two:

Όποια από τις δύο εκδόσεις και αν ενδιαφερθείτε να εγκαταστήσετε, ο τρόπος είναι ακριβώς ο ίδιος. Απλώς κατεβάστε το αρχείο .zip και αποσυμπιέστε το. Επειδή θα πρέπει να αποδεχθείτε την άδεια χρήσης του προγράμματος, θα πρέπει να το κατεβάσετε με τη βοήθεια κάποιου browser στον υπολογιστή σας και στη συνέχεια να το μεταφέρετε με scp στο Raspberry. Στη συνέχεια το αποσυμπιέζετε:

Whichever of these you may choose to install, the way is exactly the same. Just download the desired .zip file and uncompress it. Because you'll have to accept the license agreement, you have to download it using your computer's browser and transfer the file to Raspberry Pi using scp. There you can uncompress it:

elias@otherpc:~ > scp ~/Downloads/UniFi.unix.zip 192.168.1.10:/home/elias/
elias@192.168.1.10's password:
UniFi.unix.zip    100%   28MB   1.2MB/s   00:23
elias@otherpc:~ > ssh 192.168.1.10
elias@192.168.1.10's password:
.
.
elias@unificontrol:~ > cd /opt/
elias@unificontrol:/opt > sudo unzip /home/elias/UniFi.unix.zip
Archive:  UniFi.unix.zip
   creating: UniFi/
   creating: UniFi/bin/
    linking: UniFi/bin/mongod        -> /usr/bin/mongod 
.
.
.
elias@unificontrol:/opt >

Το πρόγραμμα έχει εγκατασταθεί στο Raspberry. Μένουν λίγες ακόμα λεπτές πινελιές για τη λειτουργία του. Καταρχήν το link που βρίσκεται μέσα στον κατάλογο UniFi/bin δεν χρειάζεται κάποια αλλαγή, γιατί η εγκατάσταση της MongoDB έχει φροντίσει να υπάρχει το αρχείο /usr/bin/mongod που χρειάζεται το UniFi Controller. Αυτό που χρειαζεται να γίνει, είναι να δημιουργθεί ο κατάλογος data που θα φιλοξενεί όλες τις παραμέτρους για το δίκτυό μας. Ο κατάλογος αυτός θα περιέχει και το portal της εισόδου των πελατών του ξενοδοχείου στο δίκτυο, έτσι θα πρέπει να μπορεί ο χρήστης που ανήκει στο group unifid να αλλάζει τα δεδομένα χωρίς να υπάρχουν προβλήματα με τα δικαιώματα. Επειδή θα πειράξουμε λίγο τη λίστα δικαιωμάτων, θα χρειαστεί να εγκατασταθεί και το πακέτο acl με την εντολή:

The program is now installed in Raspbian. There are some finishing touches for its correct operation. Begining with the link that lies in UniFi/bin directory, it does not need any change, since the MongoDB installation has placed the executable /usr/bin/mongod where UniFi Controller expects it. But what is necessary to be done is the creation of a directory named data. In there, all the parameters and information of the network will be stored. There will also be the entry portal of the hotel clients, so the user who belongs to unifid group must have the correct access rights for being able to alter those files without problems. We are going to change the access rights list a little bit, so we need to install acl package using the command:

elias@unificontrol:/opt > sudo apt-get install acl
...

Το επόμενο βήμα είναι να δημιουργθεί ο κατάλογος data και να του δοθούν τα κατάλληλα δικαιώματα:

The step that follows creates the data directory and gives the correct access rights to it:

elias@unificontrol:/opt > cd UniFi
elias@unificontrol:/opt/UniFi > sudo mkdir data
elias@unificontrol:/opt/UniFi > sudo chgrp unifid data
elias@unificontrol:/opt/UniFi > sudo chmod 0774 data
elias@unificontrol:/opt/UniFi > sudo chmod g+s data
elias@unificontrol:/opt/UniFi > sudo setfacl -d -m u::rwX,g::rwX,o::r data
elias@unificontrol:/opt/UniFi > ls -ld data
drwxrwsr--+ 7 root unifid 4096 May 29 13:13 data
elias@unificontrol:/opt/UniFi > getfacl data
# file: data
# owner: root
# group: unifid
# flags: -s-
user::rwx
group::rwx
other::r--
default:user::rwx
default:group::rwx
default:other::r--
elias@unificontrol:/opt/UniFi >

Πλέον είμαστε έτοιμοι να δοκιμάσουμε αν το πρόγραμμα λειτουργεί σωστά. Μην ξεχνάμε ότι η εγκατάσταση έχει γίνει με τέτοιο τρόπο που τρέχει από τον root. Για να ξεκινήσει το UniFi Controller θα πρέπει να δώσουμε την εντολή:

Now we are ready to test if the program works as expected. Do not forget that the installations has been made in a way that only root can execute it. To start the UniFi Controller run the following command from the command line interface:

elias@unificontrol:/opt/UniFi > sudo /usr/bin/java -jar /opt/UniFi/lib/ace.jar start &

Εδώ θα πρέπει να περιμένουμε λίγο χρονικό διάστημα (αρκετά δευτερόλεπτα) πριν καταφέρουμε να μπούμε στο σύστημα. Για να δοκιμάσουμε το σύστημά μας, θα πρέπει να χρησιμοποιήσουμε τον browser ενός υπολογιστή. Αν προσπαθήσουμε να μπούμε πριν το πρόγραμμα κάνει όλα τα απαραίτητα, τότε απλά θα έχουμε μήνυμα λάθους από τον browser. Αν όμως το σύστημα ετοιμαστεί τότε δίνοντας τη διεύθυνση του Raspberry με πόρτα την 8080, θα δούμε την εισαγωγική οθόνη του UniFi Controller. Η διεύθυνση που έχει αυτή τη στιγμή είναι η 192.168.1.10, οπότε η διεύθυνση που θα πληκτρολογήσουμε στον browser μας είναι η http://192.168.1.10:8080/. Η σελίδα θα κάνει redirection σε https, αλλά στην ίδια διεύθυνση και ο browser θα μας παραπονεθεί για το πιστοποιητικό της σελίδας. Όταν τελικά το αποδεχτούμε:

We will have to wait for a short time (several seconds) before trying to enter the system. To test it we will have to use the browser of another computer. If we try to enter before the program finishes all its intro tasks then we will simply receive an error message from our browser. But if the system is ready to accept connections, then by entering the IP address of the Raspberry Pi using port 8080, we will get the introduction screen of UniFi Controller. The address used during the righting of this article is 192.168.1.10, so this is the address we will type in our browser: http://192.168.1.10:8080/; the page will redirect to https protocol at the same IP address and our browser will complain about this page's certificate. When we finally accept it:

Για να σταματήσουμε το πρόγραμμα, αρκεί να τρέξουμε την εντολή:

To stop the program, we have to enter the following command:

elias@unificontrol:/opt/UniFi > sudo /usr/bin/java -jar /opt/UniFi/lib/ace.jar stop

Για την ώρα δεν χρειάζεται να κάνουμε παραμετροποίηση του συστήματος. Μπορούμε να την αφήσουμε για αργότερα, όταν όλα θα είναι έτοιμα!

For now we will not continue to any network configuration. We can leave it for later on, when everything is in place!

Δημιουργία service script

Service Script Creation

Τώρα που το σύστημα λειτουργεί, θα πρέπει να το κάνουμε να ενεργοποιείται στα κατάλληλα runlevels του Raspbian.

Now we know that the system works, we must make it automatically activated at the appropriate Raspbian runlevels.

Η διαδικασία είναι η ίδια με αυτή που περιγράφεται στο αντίστοιχο άρθρο για το openSUSE. Ο κατάλογος /etc/init.d/ περιέχει όλα τα scripts για τα services. Περιέχει κι ένα αρχείο που μας ενδιαφέρει περισσότερο, το skeleton. Αυτό είναι ένα αρχείο στο οποίο μπορούμε να βασιστούμε για να φτιάξουμε το δικό μας script, έτσι ώστε το UniFi Controller να μπορεί να ενεργοποιηθεί και να απενεργοποιηθεί όπως ακριβώς και όλα τα υπόλοιπα services που διαθέτει το σύστημα. Το αρχείο που θα δημιουργήσουμε είναι το unifid. Μπορείτε να το δημιουργήσετε μόνοι σας από την αρχή, απλά αντιγράφοντας το ακόλουθο και σώζοντάς το μέσα στον εν λόγω κατάλογο:

The procedure is the same as the one described in the similar article for openSUSE. The /etc/init.d/ contains all the scripts for all the available services. It also contains a file that we need more, named skeleton. That is the file we will be based on to create our own service script, to make UniFi Controller activated and deactivated in the same way as the rest of the system's services. The file we will create is called unifid. You can create it by yourselves from the very beginning, by simply copying and pasting the following code and saving it in the directory in question:

#! /bin/sh
### BEGIN INIT INFO
# Provides:          unifid
# Required-Start:    $local_fs $syslog $network
# Required-Stop:     $local_fs $syslog $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: unifid daemon providing Controller server for UniFi Access Points
# Description:       Start unifid to allow the UniFi Controller Software to be able to
#       control the UniFi Access Points of Ubiquity in the network. The softare runs in Java
#       and is installed in /opt/ directory.
### END INIT INFO

# Author: Elias Chrysocheris 
#

# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="UniFi Controller Service for assisting Ubiquity's UniFi Access Points"
JAVA_BIN=/usr/bin/java
NAME=unifid
MONGOD_BIN=/opt/UniFi/bin/mongod
DAEMON=/opt/UniFi/lib/ace.jar
DAEMON_ARGS="-jar $DAEMON"
SCRIPTNAME=/etc/init.d/$NAME

# Exit if Java package is not installed
[ -x "$JAVA_BIN" ] || { echo "Cannot find java executable in $JAVA_BIN, or java is not installed...";
    if [ "$1" = "stop" ]; then exit 0;
    else exit 5; fi; }

# Also, mongoDB must be installed. The extra step here is that there must be a valid link in
# /opt/UniFi/bin/mongod that points to the mongod executable
if [ ! \( -e $MONGOD_BIN \) ]
then
    echo "Cannot find mongod executable in $MONGOD_BIN, or mongoDB is not installed...";
    if [ "$1" = "stop" ]; then exit 0;
    else exit 5; fi;
fi

# Exit if the package is not installed
[ -e "$DAEMON" ] || { echo "Cannot find UniFi Controller executable in $DAEMON, or the controller software is not installed...";
    if [ "$1" = "stop" ]; then exit 0;
    else exit 5; fi; }

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh

# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions

#
# Function that starts the daemon/service
#
do_start()
{
    # Return
    #   0 if daemon has been started
    #   1 if daemon was already running
    #   2 if daemon could not be started
    start-stop-daemon --test --start --quiet --exec $JAVA_BIN -- $DAEMON_ARGS start > /dev/null \
        || return 1
    start-stop-daemon --start --quiet --exec $JAVA_BIN -- $DAEMON_ARGS start &
    RETVAL="$?"
    [ $RETVAL > 0 ] && return 2
    # Add code here, if necessary, that waits for the process to be ready
    # to handle requests from services started subsequently which depend
    # on this one.  As a last resort, sleep for some time.
}

#
# Function that stops the daemon/service
#
do_stop()
{
    # Return
    #   0 if daemon has been stopped
    #   1 if daemon was already stopped
    #   2 if daemon could not be stopped
    #   other if a failure occurred
    start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --exec $JAVA_BIN -- $DAEMON_ARGS stop
    RETVAL="$?"
    [ "$RETVAL" = 2 ] && return 2
    # Wait for children to finish too if this is a daemon that forks
    # and if the daemon is only ever run from this initscript.
    # If the above conditions are not satisfied then add some other code
    # that waits for the process to drop all resources that could be
    # needed by services started subsequently.  A last resort is to
    # sleep for some time.
    start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
    [ "$?" = 2 ] && return 2
    return "$RETVAL"
}

#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
    #
    # If the daemon can reload its configuration without
    # restarting (for example, when it is sent a SIGHUP),
    # then implement that here.
    #
    start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
    return 0
}

case "$1" in
  start)
    [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
    do_start
    case "$?" in
        0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
        2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
    esac
    ;;
  stop)
    [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
    do_stop
    case "$?" in
        0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
        2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
    esac
    ;;
  status)
    status_of_proc "$JAVA_BIN -jar $DAEMON" "$NAME" && exit 0 || exit $?
    ;;
  #reload|force-reload)
    #
    # If do_reload() is not implemented then leave this commented out
    # and leave 'force-reload' as an alias for 'restart'.
    #
    #log_daemon_msg "Reloading $DESC" "$NAME"
    #do_reload
    #log_end_msg $?
    #;;
  restart|force-reload)
    #
    # If the "reload" option is implemented then remove the
    # 'force-reload' alias
    #
    log_daemon_msg "Restarting $DESC" "$NAME"
    do_stop
    case "$?" in
      0|1)
        do_start
        case "$?" in
            0) log_end_msg 0 ;;
            1) log_end_msg 1 ;; # Old process is still running
            *) log_end_msg 1 ;; # Failed to start
        esac
        ;;
      *)
        # Failed to stop
        log_end_msg 1
        ;;
    esac
    ;;
  *)
    #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
    echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
    exit 3
    ;;
esac

Το script θα πρέπει να είναι εκτελέσιμο, οπότε όταν δημιουργηθεί στο δίσκο θα πρέπει να του ενεργοποιηθούν και τα κατάλληλα δικαιώματα εκτέλεσης. Επίσης, η δημιουργία του γίνεται από τον χρήστη root, αλλοιώς το σύστημα θα αρνηθεί να το σώσει μέσα στον κατάλογο init.d. Τέλος θα πρέπει να γίνουν update τα links των καταλόγων rc?.d, έτσι ώστε το service να ξεκινάει ή να σταματάει αυτόματα, ανάλογα με το runlevel στο οποίο μεταπηδάει το Raspbian. Οι εντολές για τα δικαιώματα και την ενημέρωση των runlevels είναι οι ακόλουθες:

The script must be marked executable, so when it is created in the disc we must alter its access rights. Another tip is that it ust be created from the root user, or the system will deny its saving into init.d. Last, the links of all rc?.d directories must be updated, for the service to be started or stopped automatically, according to runlevel transitions of the operating system. The commands for altering the access rights and updating the runlevel links are:

elias@unificontrol:/opt/UniFi > cd /etc/init.d/
elias@unificontrol:/etc/init.d > sudo chmod 0755 unifid
elias@unificontrol:/etc/init.d > sudo update-rc.d unifid defaults
update-rc.d: using dependency based boot sequencing
elias@unificontrol:/etc/init.d > 

Μπορεί να γίνει να δοκιμή του script που μόλις ενεργοποιήθηκε δίνοντας τις ακόλουθες εντολές και κοιτάζοντας τις αποκρίσεις:

We can test the newlly created and activated script by executing the folowing commands and observe their response:

elias@unificontrol:/etc/init.d > sudo /etc/init.d/unifid start
elias@unificontrol:/etc/init.d > sudo /etc/init.d/unifid status
[ ok ] unifid is running.
elias@unificontrol:/etc/init.d > sudo /etc/init.d/unifid stop
elias@unificontrol:/etc/init.d > sudo /etc/init.d/unifid status
[FAIL] unifid is not running ... failed!
elias@unificontrol:/etc/init.d > 

Αν όλα πήγαν καλά, τότε μετά από μια επανεκκίνηση αν εκτελέσουμε την εντολή ps aux | grep ace.jar θα πρέπει να δούμε τα ακόλουθα:

If everything went right, after a restart of Raspbian, using the command ps aux | grep ace.jar we must get something like:

elias@unificontrol:~ > ps aux | grep ace.jar
root      3189 54.0  5.2 370688 25212 ?        Sl   23:43   0:16 /usr/bin/java -jar /opt/UniFi/lib/ace.jar start
elias     3241  0.0  0.1   3548   892 pts/0    S+   23:43   0:00 grep --color=auto ace.jar
elias@unificontrol:~ > 

Αυτό που μας ενδιαφέρει είναι η πρώτη γραμμή που δείχνει πως ένα process τρέχει αυτή τη στιγμή στον επεξεργαστή κι έχει την εντολή ενεργοποίησης του service του UniFi Controller. Η συνέχεια είναι απλή. Ανοίγουμε και πάλι τον browser και δίνοντας την IP διεύθυνση του Raspberry με την πόρτα 8080, όπως κάναμε και πριν, ξεκινάμε την παραμετροποίηση του συστήματος των Access Points. Όταν όλα τελειώσουν μπορούμε να έχουμε μια εικόνα σαν αυτή:

What we are interested in, is the first line showing there is an active process running in our processor, started by the same command we used to start the UniFi Controller. What follows is natural; We open a browser in our computer and by entering the Raspberry's IP address and port 8080, as we did before, we can start the configuration of our Access Points. When everything is done we must get a page like that:

Συμπεράσματα

Conclutions

Το Raspberry Pi, είναι ένα gadgetάκι που, μπορεί κάποιος να μη μείνει ικανοποιημένος αν προσπαθήσει να το χρησιμοποιήσει όπως ένα Desktop υπολογιστή. Όταν το χρησιμοποιήσετε απλά για internet κ.λ.π. θα διαπιστώσετε ότι μοιάζει πολύ με ένα υπολογιστή τεχνολογίας εποχής του KDE3. Ναι μεν μπορείς να κάνεις κάποια δουλειά, αλλά οι χρόνοι καθυστέρησης σε γυρίζουν λίγο πίσω... Από την άλλη, σαν ένας μικρός server έχει αρκετά πλεονεκτήματα. Έχει ικανοποιητική ταχύτητα για τη διαχείριση ενός μικρού δικτύου. Μπορεί να αναλάβει "μικροδουλειές" όπως backup/file server, firewall ή ακόμα και για να τραβάει φωτογραφίες σαν σύστημα παρακολούθησης/ασφάλειας. Στη δική μας περίπτωση, αυτό που μας ενδιέφερε είναι να μπορέσει να λειτουργήσει ως διαχειριστής δικτύου ξενοδοχείου και αυτή τη δουλειά την κάνει αρκετά καλά.

Raspberry Pi is a small gadget that someone may not be satisfied if he/she uses it as a desktop computer. If you use it simply for internet browsing etc. you will find out it is very similar, in terms of processing power, to a computer that used KDE3. It is true you can do some work, but the execution times takes you a little bit back in time... In contrast, working as a small server has many advantages. Its speed is satisfactory for using in a small network. It can handle some simple tasks such as a backup/file server, a firewall or even taking photos as an area survailance/security system. In our case, what we were interested in was to be able to handle access control and portal serving in a hotel's network. And that is a job that can handle very well.

Μια ακόμα δυνατότητα είναι πως μπορεί πολύ εύκολα να τροφοδοτηθεί από μια επαναφορτιζόμενη μπαταρία. Λόγω την μικρής του κατανάλωσης μια τέτοια μπαταρία είναι ικανή να το κρατήσει σε λειτουργία για πραγματικά πολλές ώρες, σε περίπτωση διακοπής της ΔΕΗ.

Another posibility is that it can be easily powered by a rechargable battery. Due to its low power consumption a battery like that can keep it functional even during long time power failures of the power company.

Όσο για την τιμή του, είναι ιδανική για αυτό που προσφέρει και αυτά που μπορεί να κάνει, ειδικά σαν "δικτυακό βοήθημα". Οι γενικές εντυπώσεις μας είναι άριστες!

And for its price, it is ideal for what it can offer and perform, aspecially as a "network assistant". Our general impression is more than surprising!

Ηλίας Χρυσοχέρης

Elias Chrysocheris