Whois skulle lika gärna kunna ersättas av publikt API, representerat i en central relationsdatabas, men det finns ingen drivkraft att ändra på tjänsteprotokollets utformning.

Internet består av en mängd standarder som implementeras med varierad noggrannhet av olika aktörer. I detta inlägg kan du läsa om Whois, en standard för hantering av domännamn, som definitionsmässigt varken förändrats eller utvecklats nämnvärt sedan Internet föddes. Definitionen är dock så pass övergripande att det finns gott om utrymme för variation i de olika implementationer som än idag hanterar majoriteten av Internets toppdomäner.

Vad är Whois?

Det centrala organet IANA innehåller en förteckning över det stora antal databaser som implementerar Whois, och som var för sig kan frågas för utdrag om registreringar under toppdomäner som de ansvarar för. En grundläggande funktionalitet som ingår i Whois är möjligheten att avgöra huruvida en domän är fri att registrera eller inte.

I de flesta Unix- och Linuxsystem ingår Whois som terminalkommando. Om du exempelvis har en Mac kan du själv starta applikationen Terminal och sedan skriva whois google.se för att ställa en fråga om google.se mot den svenska databasen. Då får du i engelsk text reda på att MarkMonitor Inc 2008-10-20 registrerade domänen åt Google och att registreringen löper ut 2013-10-20 om den inte förnyas.

# Copyright (c) 1997- .SE (The Internet Infrastructure Foundation).
# All rights reserved.

# The information obtained through searches, or otherwise, is protected
# by the Swedish Copyright Act (1960:729) and international conventions.
# It is also subject to database protection according to the Swedish
# Copyright Act.

# Any use of this material to target advertising or
# similar activities is forbidden and will be prosecuted.
# If any of the information below is transferred to a third
# party, it must be done in its entirety. This server must
# not be used as a backend for a search engine.

# Result of search for registered domain names under
# the .SE top level domain.

# The data is in the UTF-8 character set and the result is
# printed with eight bits.

state:            active
domain:           google.se
holder:           mmr8008-53808
admin-c:          -
tech-c:           -
billing-c:        mmr8008-132163
created:          2008-10-20
modified:         2012-10-30
expires:          2013-10-20
transferred:      2009-03-06
nserver:          ns1.google.com
nserver:          ns2.google.com
nserver:          ns3.google.com
nserver:          ns4.google.com
dnssec:           unsigned delegation
status:           ok
registrar:        MarkMonitor Inc

Formateringen av resultat från olika databaser är medvetet designad för mänsklig avläsning. Det finns tyvärr inte någon övergripande specifikation av datum-format eller representation av händelser eller kontaktuppgifter som relaterar till de registrerade domännamnen. Den som har hyfsade språkkunskaper kan läsa av de absolut flesta utdragen från olika databaser manuellt. En bidragande orsak till designutförandet kan vara ett försök att hindra automatiserad spridning till 3:e part, något som inte är tillåtet enligt tjänstens användarvillkor – security through obscurity helt enkelt.

Whois som stöd för webbanalys

Den största anledningen till att vi på Jajja är intresserade av Whois är för att det kan användas för att avgöra domänålder och hitta andra intressanta datum som har med domäners giltighet att göra. Domänålder används i våra analyser av webbplatser eftersom det är en av signalerna till Googles ranking-algoritm. Google håller gissningsvis reda på domänålder själva enligt egna regler, men eftersom vi inte har tillgång till historik per domän sedan Google började indexera Internet får Whois duga som approximation.

Whois skulle lika gärna kunna ersättas av publikt API, representerat i en central relationsdatabas, men det finns ingen drivkraft att ändra på tjänsteprotokollets utformning. Möjligen förändras synen på detta när ett stort antal nya toppdomäner så småningom behöver passas in i befintliga strukturer på Internet. Vi kan varken vänta eller hoppas på att det blir så, istället är det hög tid att implementera en heltäckande Whois-parser för maskinell avläsning!

Om du inte är intresserad av ett strukturellt förslag för att koda en egen Whois-parser, hoppa istället till den sensationella iaktagelsen om Whois och Google.

Ett utkast till en Whois-parser

För att förstå hur man skall angripa problemet att designa en komplett parser kan det vara värt att först titta på definitionen. Det som är absolut mest märkbart i specifikationen är avsaknaden av avgränsningar. Dokumentet RFC 3912 från 2004 beskriver protokollet som kan förenklas så här:

En WHOIS-tjänst lyssnar på TCP-port 43. Frågor mot tjänsten ställs med en textrad, avslutad med ASCII-CR och sedan ASCII-LF. Svar från tjänsten kan innehålla flera rader text och avslutas i och med att uppkopplingen bryts.

I tidiga implementationer av Whois gick det utmärkt att skicka fritextsökningar på flera fält till databaserna, men nu används normalt endast exakt domän som fråga. Det kan verka otroligt simpelt och är ganska lätt att utforska med terminalkommandot Telnet. Om du tidigare testade Whois i din terminal kan du istället prova med kommandot telnet whois.iis.se 43, varpå du kan mata in en rad text som lämpligen bör vara en svensk domän-adress. Som du kanske märker får vi samma typ av svar som tidigare. Den enda väsentliga skillnaden är att vi nu manuellt angivit vilken databas som används. Detta är inte heller speciellt komplicerat att åstadkomma med kod för automatisering av förfrågningar. Svårigheten ligger istället i att känna till strukturen på svaret hos de olika implementationerna som databaserna använder. För att konkretisera problembeskrivningen använder vi den danska Whois-databasens svar.

# Hello 82.99.58.1. Your session has been logged.
#
# Copyright (c) 2002 - 2012 by DK Hostmaster A/S
#
# The data in the DK Whois database is provided by DK Hostmaster A/S
# for information purposes only, and to assist persons in obtaining
# information about or related to a domain name registration record.
# We do not guarantee its accuracy. We will reserve the right to remove
# access for entities abusing the data, without notice.
#
# Any use of this material to target advertising or similar activities
# are explicitly forbidden and will be prosecuted. DK Hostmaster A/S
# requests to be notified of any such activities or suspicions thereof.

Domain:               google.dk
DNS:                  google.dk
Registered:           1999-01-10
Expires:              2013-03-31
Registration period:  1 year
VID:                  no
Status:               Active

Nameservers
Hostname:             ns1.google.com
Hostname:             ns2.google.com
Hostname:             ns3.google.com
Hostname:             ns4.google.com

# Use option --show-handles to get handle information.
# Whois HELP for more help.

Vi antar att problematiken att fråga rätt databas är löst och nöjer oss med att försöka matcha relevanta datum för händelser, som registrering, uppdatering och förfall. Då återstår bara att överbrygga skillnaderna i formatering mellan de olika implementationerna, och kanske framförallt att identifiera de rader som innehåller den data vi är intresserade av. Eftersom svar från Whois enligt specifikationen är radorienterade borde en uppsättning radorienterade regler räcka för att angripa problemet. Vi kan kalla dessa regler för funktorer och låta dem bestå av ett reguljärt uttryck som används som mönster för att matcha rätt rad. Funktorn måste också ha tillgång till en implementation av logik som översätter det aktuella fältet till ett standardiserat format. Lyckligtvis finns det i nästan alla kodspråk väldefinierade funktioner för formatering av datum. Ett enkelt datummönster kan räcka för att representera denna översättningslogik.

Ett sätt att representera våra parserdefinitioner för de olika toppdomänerna skulle kunna vara JSON. JSON är en enkel markup för strukturerad data. I den representationen kan en funktor för registreringsdatum se ut som följer:

{
  "field": "registered",
  "pattern": "Registered: +([0-9]{4}-[0-9]{2}-[0-9]{2})",
  "implementation": "Date",
  "configuration": [
    {
      "field": "format",
      "value": "yyyy-MM-dd"
    }
  ]
}

Vi måste dock anta att det kan komma att finnas intressant data där radvis matchning inte är helt tillräcklig. Om vi exempelvis är intresserade av datum när registreringen uppdaterats stöter vi på patrull redan i Danmark, vars Whois-implementation skiljer sig från de flesta övriga. Datumet representeras nämligen av ett intervall relaterat till utgångsdatumet för registrering, exempelvis 1 year. Därmed kan mer än en rad vara avgörande för att få ut ett specifikt värde. För mer avancerade fält som vi för tillfället inte är intresserade av är detta ett vanligt förhållande. Vissa funktorer behöver alltså känna till innehåll som andra funktorer matchat ut. Det kan representeras i trädform där nästlade funktorer får tillgång till det som hittats tidigare i hierarkin. Vi modifierar exemplet i JSON att tillåta detta:

{
  "field": "expires",
  "pattern": "Expires: +([0-9]{4}-[0-9]{2}-[0-9]{2})",
  "implementation": "Date",
  "configuration": [
    {
      "field": "format",
      "value": "yyyy-MM-dd"
    }
  ],
  "functors": [
    {
      "field": "modified",
      "pattern": "Registration period: +([0-9]+ [a-z]+)",
      "implementation": "SubtractInterval"
    }
  ]
}

Förtom datum för registrering, uppdatering och förfall kan det vara intressant att veta huruvida domänen är ledig att registrera eller ej. Faktum är att vissa Whois-databaser implementerar detta som enda typ av giltighetsinformation för sina domäner. De flesta implementationerna har ett specifikt svar för att domänen är ledig. För det danska exemplet skulle en komplett parserdefinition vara:

{
  "parser": {
    "functors": [
      {
        "field": "registered",
        "pattern": "Registered: +([0-9]{4}-[0-9]{2}-[0-9]{2})",
        "implementation": "Date",
        "configuration": [
          {
            "field": "format",
            "value": "yyyy-MM-dd"
          }
        ]
      },
      {
        "field": "expires",
        "pattern": "Expires: +([0-9]{4}-[0-9]{2}-[0-9]{2})",
        "implementation": "Date",
        "configuration": [
          {
            "field": "format",
            "value": "yyyy-MM-dd"
          }
        ], 
        "functors": [
          {
            "field": "modified",
            "pattern": "Registration period: +([0-9]+ [a-z]+)",
            "implementation": "SubtractInterval"
          }
        ]
      },
      {
        "field": "isNotFound",
        "pattern": "No entries found for the selected source.",
        "implementation": "NotFound"
      }
    ]
  }
}

Fler tips på vägen mot en komplett Whois-parser

Om du nu blir intresserad av att koda en egen parser för avsläsning av registreringsdatum kan jag rekommendera att till en början begränsa dig till en eller ett par toppdomäner. Om avsikten sedan är att bli heltäckande kommer din parser behöva stöd för olika teckenuppsättningar som EUC-KR för Korea eller ISO-8859-1 för Portugal.

Många implementationer av Whois använder samma motor för att generera svar, varför det finns en överrepresentation av ett antal datummönster. Med lite händighet i ett scriptspråk går det därför ganska bra att generera mallar för specifika parser-definitioner, något som sedan måste granskas manuellt för att inte missa eventuellt tvetydiga datum. Användandet av scriptspråk för att generera eller bearbeta data är för övrigt intressant i många andra problemställningar, så det hade jag tänkt att vi skulle återvända till i ett kommande inlägg.

En spännande upptäckt när vi implementerade vår egen version av parsern var att den amerikanska Whois-databasen som hanterar .com, .net och .org fortfarande har stöd för wildcardsökningar och att det dessutom är förvalt. Faktum är att…

Whois används för att “hacka” Google

För utveckling och validering av vår Whois-parser använde vi orden Google, Poker och Hotel som testdata. Google finns nämligen registrerat under de flesta toppdomänerna likaså Poker och Hotel. När vi så kom till de amerikanska domänerna möttes vi av förvåning när en lista av tillsynes registrerade domäner fanns med i svaret till frågan whois google.com, bland andra:

  • GOOGLE.COM.ZOMBIED.AND.HACKED.BY.WWW.WEB-HACK.COM
  • GOOGLE.COM.IS.NOT.HOSTED.BY.ACTIVEDOMAINDNS.NET
  • GOOGLE.COM.IS.HOSTED.ON.PROFITHOSTING.NET

Whois är nära relaterat till DNS, det tjänsteprotokoll som ansvarar för uppslag av domännamn och deras koppling till internetadresser, som gör det möjligt för oss att hitta rätt på Internet. Den amerikanska Whois-databasen implementerad av Internic är så pass tätt knuten till DNS att den lyssnar på och förmedlar information som namnservrar (DNS) innehåller. Dessutom är sökning över flera olika typer av utdrag standard i Internics implementation, vilket gör att servernamn från DNS blandas med registrerade domännamn. Detta är inte en fråga om ett intrång hos Google, utan är helt enkelt hur domändata representeras i databasen. Det går att begära exakt matchning av domäner genom att utöka frågan till whois "domain google.com".

Bakgrunden till de falska utdragen är gissningsvis en önskad publicitet. För att inte späda på eller bidra till fenomenet ytterligare har vi valt att filtrera den stora listan till det fåtal servernamn i exemplet ovan, men prova gärna själv om du är intresserad. Dessutom är Google inte de enda som drabbats av denna typ av relativt osynlig SPAM. Kan du komma på någon av de andra?