Toen ik aan de slag ging met Apache en Apache-logbestanden (zie ook o.a. dit bericht) heb ik er voor gekozen om in de logbestanden de IP-nummers op te laten slaan in plaats van de hostnamen van de computers die een pagina opvragen. Dat heb ik gedaan omdat in de documentatie wordt aangegeven dat dat vertraging oplevert omdat dan bij elke regel een netwerkactie nodig is. De server krijgt namelijk alleen het IP-nummer (bijvoorbeeld 134.58.253.131) en moet het hostadres (in dit geval webcache-kotnet-1.kuleuven.ac.be) dan steeds opzoeken.
Het ligt voor de hand om dat bijvoorbeeld pas bij het importeren of verwerken van de logbestanden te doen omdat je het dan niet voor elke regel doet, maar voor elk ip-adres eenmalig. Dus moest ik gaan uitzoeken hoe ik dat kon doen in PHP.
Dat was echter niet alles. Ik wist ook dat het mogelijk moest zijn om aan de hand van een IP-nummer te achterhalen in welk land de gebruiker van dat IP-nummer woont. En dat wilde ik natuurlijk ook kunnen. Aan de slag dus weer met PHP.
Voor de ongeduldigen
het werkend eindresultaat
Van IP-nummer naar hostnaam
Het vertalen van IP-nummer naar hostnaam was redelijk simpel. PHP kent daarvoor de functie gethostbyaddr die een IP-nummer indien mogelijk vertaald naar een hostnaam. Niet alle IP-nummers zijn te vertalen. Zo worden de IP-nummers van Fontys werkplekken niet vertaald naar hostnamen. De functie gethostbyaddr geeft dan gewoon het IP-nummer als resultaat.
Van IP-nummer naar land
Voor wat betreft het zoeken van de bijbehorende landen wist ik dat er databases in omloop waren die IP-series koppelen aan land van herkomst. Als je bijvoorbeeld naar een IP-adres uit de aan Fontys beschikbaar gestelde serie zoekt bij RIPE, dan zie je dat Fontys de beschikking heeft over het bereik 145.85.0.0 – 145.85.255.255. Kortom, alle IP-nummers van 145.85.0.0 tot 145.85.255.255 hebben hun herkomst in Nederland. Zoek ik op het eerder als voorbeeld gebruikte 134.58.253.131 dan zie ik dat het bereik 134.58.0.0 – 134.58.255.255 zijn herkomst heeft in België.
Op basis van deze informatie kun je dus een tabel maken met groepen IP-nummers en het land waar ze hun herkomst hebben. Het is echter niet handig daar de IP-nummers in deze vorm voor te gebruiken. Want hoewel wij eenvoudig en snel kunnen herkennen dat 145.85.2.34 een IP-nummer uit de Fontys-reeks is, zal een computerprogramma bij grote aantallen IP-nummer in het ergste geval alle vier de deelgetallen van de ondergrens en eveneens van de bovengrens individueel moeten vergelijken om te bepalen of een IP-nummer in het bereik ligt. Het is daarom handiger het IP-nummer naar een decimaal getal om te zetten dat in één keer te vergelijken is met het te onderzoeken IP-nummer.
En ook daar blijkt PHP een functie voor in huis te hebben: ip2long. De functie zet het IP-nummer van ‘decimale punt-notatie’ om in een decimaal getal. Dat decimaal getal overigens, is net zo bruikbaar als adres als een IP-nummer in punt-notatie, het ping-commando bijvoorbeeld accepteert het gewoon als alternatieve notatie:
Hoe is een IP-nummer opgebouwd
Het berekenen van de decimaal getal-notatie is niet moeilijk als je weet dat in de op dit moment meest gebruikte IP-adressering ( IPv4) we gebruik maken van ’32-bits’ adressen. Hiermee kun je 4.294.967.296 verschillende adressen maken. Je kunt zo’n adres zien als het telefoonnummer van een computer. IP-adressen bestaan dus uit een combinatie van 32 enen of nullen (bits). Het IP-adres voor www.fontys.nl is: 10010001010101010000001000011110. Maar dat leest niet echt lekker en de kans de fouten is aanzienlijk. Een eerste stap zou zijn om het adres op te delen in vier stukken van acht cijfer: 10010001.01010101.00000010.00011110
Dat is overigens geen toevallig gekozen indeling: het is steeds de omvang van 1 Byte (bestaande uit 8 bits). Punten helpen een beetje, maar nog niet echt veel. Een stap verder is daarom om die individuele binaire getallen tussen de punten om te zetten naar decimale getallen die korter zijn en gemakkelijker te onthouden.
Zoals je wellicht weet werkt het binaire stelsel alleen met enen en nullen en krijg je dus de volgende vertalingen van binair naar decimaal:
Bin => Dec
0 => 0
1 => 1
10 => 2 (2^1)
11 => 3
100 => 4 (2^2)
101 => 5
110 => 6
111 => 7
1000 => 8 (2^3)
1001 => 9
1010 => 10
100000000 => 256 (2^8 )
Als je er zelf mee aan de slag wilt, kun je ook de rekenmachine van Windows gebruiken. Zet die op ‘wetenschappelijk’ en je kunt getallen converteren van (o.a) binair naar decimaal door de rekenmachine op bijvoorbeeld binair te zetten, het binaire getal in te voeren en dan om te schakelen naar de decimale stand. Het getal wordt dan automatisch omgerekend.
Goed, terug naar ons binair getal: 10010001.01010101.00000010.00011110
Dat bestaat uit deze vier binaire getallen die we individueel omrekenen:
10010001 => 145
01010101 => 85
00000010 => 2
00011110 => 30
En dat kun je nu schrijven als: 145.85.2.30 het inmiddels vertrouwde IP-nummer in decimale punt-notatie.
Van decimale punt-notatie naar decimaal getal
Als je een IP-nummer in zijn decimale punt-notatie wilt omrekenen naar een decimaal getal, gaat dat als volgt:
decimale punt-notatie => 145.85.2.30
binaire punt-notatie => 10010001.01010101.00000010.00011110
binair getal zonder punten => 10010001010101010000001000011110
omrekenen naar decimaal getal => 2438267422
(hier zou je in PHP overigens de bindec-functie voor kunnen gebruiken)
Mocht je het ooit ‘handmatig’ willen/moeten berekenen, dan kan het ook zo:
145.85.2.30 => (145 * 2^24) + (85 * 2^16) + (2 * 2^8 ) + (30 * 2^0) => (145 * 16.777.216) + (85 * 65.536) + (2 * 256) + (30) = 2438267422
Van getal naar land, stap 1
Goed, nu hebben we een getal, hoe komen we nu aan de benodigde reeksen om daadwerkelijk een vergelijking te maken? Dat hoef je gelukkig niet zelf te doen. Ik ging eerst verder zoeken dan nodig bleek. Een zoekopdracht bij Google bracht me bij IP-to-Country.com waar ik een CSV-bestand en voorbeeld-PHP-script kon downloaden. Dat werkte wel, maar er waren ook nog best wat adressen die niet in het bestand zaten. Zo zaten geen van de universiteiten en hogescholen (de 145.* reeks) in het bestand.
Toen realiseerde ik me dat ik al een hele tijd een rapportage-tool voor mijn weblog gebruik dat ook informatie over het land van herkomst geeft: BBCLONE. Het tool is ook in PHP geschreven en levert de landendatabase als set tekstbestanden mee. De bestanden splitsen de reeksen op naar het eerste nummer van het decimaal punt-genoteerde IP-nummer. Dus de informatie voor ons 145.85.2.30 nummer zit in het bestand 145.inc (in de ip2ext map).
De eerste regel van dat bestand bevat deze informatie:
nl|2432696320|14680064
De nl zal bekend zijn. Het tweede getal (2432696320) is een decimale weergave van 145.0.0.0. Het derde getal is de delta, d.w.z. dat de reeks loopt t/m 2432696320 + 14680064 oftewel 2447376384 oftewel 145.224.0.0
Het script loopt elke regel in het bestand door (30 in het 145.inc-bestand) om te kijken of het IP-nummer in de range valt.
Van getal naar land, backup-mogelijkheid
Mocht het getal niet voorkomen in de bestanden (ook de bestanden van BBClone zijn niet 100% compleet, is ook bijna niet mogelijk), dan gebruikt het script een slimigheidje om toch nog te proberen te achterhalen waar de bezoeker vandaan komt: de hostnaam.
Neem nou ons steeds terugkerend voorbeeld: www.fontys.nl
Ook als het IP-nummer niet in de bestanden voor komt dan kun je bij .nl adressen er vanuit gaan dat de bezoeker uit NL (Nederland dus) komt. Natuurlijk een server met een .nl adres kan ook in het buitenland gehost worden, maar het gaat hier voornamelijk om bezoekers, dus mensen die inbellen bij een provider of een breedbandverbinding hebben bij een provider in het land zelf. En 100% nauwkeurig hoeft het natuurlijk ook weer niet te zijn.
Het complete script
Ik heb de code van het script dat je hier kunt uitproberen online gezet. Ik weet niet 100% zeker wat ik aan extra informatie etc. moet toevoegen vanwege het gebruik van de BBClone-code. BBClone wordt onder de GPL-licentie beschikbaar gesteld. Zover ik weet betekent dat dat ik dat ook moet doen omdat mijn code er gebruik van maakt. Bij deze dan.
In welke land woon jij?
Gewoon effe checken via http://www.geo-loc.com/index_en.php
Toch?
Dat kan, maar ik wil die informatie in een script kunnen benaderen.
één toepassing is bijvoorbeeld het herkennen van ‘verdachte’ referers. Voor een Nederlandstalige weblog zijn 98% van de verwijzingen die niet uit Nederland of België komen én niet van een zoekmachine komen sp@mmers.
Als mijn site die zelf al voor me weet te verzamelen en ik alleen maar hoef te bevestigen dat ze aan de block-lijst moeten worden toegevoegd scheelt dat heel wat moeite.
Maar dan heb ik niets aan zo’n mooi plaatje.
I C
en bestaan er ook uitwisselingsprogramma’s voor block-lijsten? Of ook voor mij begrijpelijke how-to’s?
Want hoewel onder de indruk van zoveel technische vaardigheden en stiknieuwsgierig ben ik ook errug lui
Die wat ik gebruik is een combinatie van eigen knutselwerk + gebruik van code van anderen. Andere kant en klare producten zijn o.a. beschikbaar voor:
* WordPress
* MT
* Nucleus
* Pivot
Maar die heb ik zelf niet getest.
Ik heb inmiddels die nucleus-tool geinstalleerd (genoemde link is overigens ‘forbidden’, deze werkt wel).
Deze tool maakt inderdaad gebruik van een openbare bloklijst.
Voor meer info over mijn ervaringen met die nucleus-tool: zie het item op mijn weblog.