Apache Webserver rules, Nginx rocks

Eine kürzlich veröffentlichte Statistik von Netcraft bescheinigt Apache den absoluten Spitzenplatz bei den Webservern weltweit. Mit knapp 58% im Januar 2012 ist er mehr als 4mal so verbreitet als die Nummer zwei der Liste.

Nginx, ein weiterer Open Source Webserver (BSD Lizenz), hat nach dieser aktuellen Studie gerade Microsoft IIS überholt und ist mit 12,18% (MS IIS 12,14%) Marktanteil auf Platz 2.

Es ist allerdings zu bemerken, dass die Anzahl Webserver mit Apache schlagartig im Mai-Juni 2011 zunimmt (fast eine Verdoppelung). Dieser „Sprung“ lässt sich wahrscheinlich nicht (nur) mit einer spontanen Zunahme an Apache-Webservern erklären. Vermutlich ist eine veränderte Messmethode der Grund..? Jedenfalls wäre der Vorsprung immernoch doppelt so hoch, wenn die Zunahme „linear“ verlaufen würde. Immer noch beachtlich!

E-Mail Adressen mit Javascript bzw. JQuery vor Grabbern schützen

Wenn man seine E-Mail Adresse oder die von anderen einfach als HTML Code veröffentlicht, besteht die Gefahr, dass die Adressen von Skripten maschinell eingelesen werden, mit dem Zweck diese als Empfänger für Spam zu nutzen. Es gibt einige mehr oder minder effektive Möglichkeiten, die Adressen für Homepagebesucher sichtbar zu machen, aber das automatisierte Ablesen zu erschweren.

Eine davon ist die Adresse von eindeutigen Merkmalen wie @ (jede E-Mail Adresse besitzt bekannterweise genau ein @) oder . (als Trennzeichen zwischen Domain und TLD) zu bereinigen, in dem man diese Zeichen durch Marker ersetzt und zur Laufzeit dann mit den richtigen Zeichen austauscht.

Also, anstatt im HTML Quelltext zu schreiben
<a href=“mailto:mailname@domain.tld“>mailname@domain.tld</a>
schreiben wir
<span class=“amailto“>mailname at domain dot tld</span>
Javascript (JQuery):
$(document).ready(function(){
  var at = / at /;
  var dot = / dot /g;
  $(„span.amailto“).each(function(){
    var addr = $(this).text().replace(at,“@“).replace(dot,“.“);
    $(this).after(„<a href=’mailto:“+addr+“‚ title=’E-Mail senden‘>“+ addr +“</a>“);
    $(this).remove();
  });
});

Telko-Maker – Telefonkonferenz: „Bin drin“

Dass es bereits viele Telefonkonferenzlösungen gibt, heisst noch lange nicht, dass man für sich die passende gefunden hat. Telko-Maker vereint einzigartige Funktionen, um das gemeinsame Telefonieren einfacher und bequemer zu gestalten.

Nutzen Sie beispielsweise das Einladungssystem, um mehrere Personen einzuladen und bieten Sie ihnen mehrere Terminmöglichkeiten zur Teilnahme an. Telko-Maker wird anhand der Antworten automatisch den ersten gemeinsamen Termin aufsetzen und die Teilnehmer benachrichtigen…

Telko-Maker bündelt in wenigen Optionen ein doch mächtiges Interface sowohl für gelegentliche Nutzer als Dauerkonferenzler. Momentan ist die Software im Beta Status kostenfrei nutzbar, Sie können sich einfach auf http://www.telko-maker.com anmelden.

Wie kann man die Rufnummer bei Telefonaten zwischen Sipgate Teilnehmern und Asterisk anzeigen (anstatt interne Sipgate-ID)?

AsteriskAnrufe zwischen Sipgate Teilnehmern werden automatisch als SIP-Anrufe geroutet, selbst wenn man die „externe“ Telefonnummer anruft. Das hat den Vorteil, dass die Anrufe zwischen den Sipgate Teilnehmern nichts kosten, da die Telefonate über Internet abgewickelt werden. Schön wäre es aber auch zu wissen, wer mich anruft 😉

Problem:
In der From-Header steht dann nicht die Telefonnummer des Anrufers sondern die SIP-URL (z.B. <sip:12345e0@sipgate.de>). Die von Asterisk gesetzte Variable CALLERID(num) beinhaltet dann nur noch die Sipgate SIP-UserID wie z.B. 12345e0. Die an Asterisk angeschlossenen Telefone können meistens damit nichts anfangen. Wenn die ID einen Buchstaben enthält (hier im Beispiel ‚e‚), führt es dazu, dass manch ältere Telefone gar keine Rufnummer anzeigen. Besonders ärgerlich ist es, wenn man einen Anruf verpasst hat und die Rufnummer nicht mehr zuordnen kann, wer tatsächtlich angerufen hat.

Lösungsweg:
Schaut man sich die SIP Header an, stellt man fest, dass die gewünschte Information in dem Headerelement „P-Asserted-Identity“ enthalten ist:

INVITE sip:5000@10.0.0.33 SIP/2.0
...
From: <sip:12345e0@sipgate.de>;tag=CAFEBABE
To: <sip:072198765432@sipgate.de>
Contact: <sip:12345e0@12.34.56.78;uniq=CAFEAFFE23>
...
P-Asserted-Identity: <sip:072112345678@sipgate.de>

Bei anderen Anbietern kann das Format abweichen. Mehr dazu in http://www.ietf.org/rfc/rfc3325.txt.

Zwecks Demonstration habe ich einen kleinen Dialplan für Asterisk geschrieben:

; debug
exten => 5000,1,NoOp(Caller-ID: ${CALLERID(all)})
exten => 5000,2,NoOp(SIP From: ${SIP_HEADER(From)})
exten => 5000,3,NoOp(SIP To  : ${SIP_HEADER(TO)})
exten => 5000,4,NoOp(SIP PAI : ${SIP_HEADER(P-Asserted-Identity)})

; try to extract phone number from sip header P-Asserted-Identity
exten => 5000,5,Set(FON=$["${SIP_HEADER(P-Asserted-Identity)}" : "<sip:([0-9]+)"])
exten => 5000,6,ExecIf($[${ISNULL(${FON})}=0]?Set(CALLERID(num)=${FON}))

; debug
exten => 5000,7,NoOp(Caller-ID: ${CALLERID(all)})
...

Erläuterung:
5: Wir extrahieren die Nummer mit RegExp und speichern das Ergebnis in die Variable FON.
6: Falls FON nicht null ist, ersetzen wir die CALLERID(num) mit dem Wert von FON.

Hier zwei UseCases und Ausgabe von Asterisk:
Teinehmer für das Beispiel (Telefonnummer, IPs sowie alle TAGs sind verschleiert).
Angerufene (Asterisk mit Sipgate-Account):
– Telefonnumber = 072198765432
Anrufer 1 (Fritzbox mit Sipgate-Account):
– Sipgate ID = 12345e0
– Telefonnumber = 072112345678
Anrufer 2 (Mobil):
– Telefonnumber = 017112345678

Case 1: Anrufer 1 (sipgate -> sipgate):

-- Exec...1] NoOp("SIP/sipgate.de-000000b6", "Caller-ID: "" <12345e0>") in new stack
-- Exec...2] NoOp("S..b6", "SIP From: <sip:12345e0@sipgate.de>;tag=CAFEBABE") in new stack
-- Exec...3] NoOp("S..b6", "SIP To  : <sip:072198765432@sipgate.de>") in new stack
-- Exec...4] NoOp("S..b6", "SIP PAI : <sip:072112345678@sipgate.de>") in new stack
-- Exec...5] Set("S..b6", "FON=072112345678") in new stack
-- Exec...6] ExecIf("S..b6", "1?Set(CALLERID(num)=072112345678)") in new stack
-- Exec...7] NoOp("S..b6", "Caller-ID: "" <072112345678>") in new stack
-- Exec...8] ...

Exec…5: Die externe Rufnummer des Anrufers wurde in FON reingeschrieben
Exec…6: 1? => Kondition erfüllt => ersetze CALLERID(num)
Exec…7: Verifizierung, dass die Nummer ersetzt wurde (vgl. Exec…1)

Case 2: Anrufer 2 (mobil -> sipgate):

-- Exec...1] NoOp("S..b8", "Caller-ID: "017112345678" <017112345678>") in new stack
-- Exec...2] NoOp("S..b8", "SIP From: "017112345678" <sip:017112345678@sipgate.de>;tag=cafebabe") in new stack
-- Exec...3] NoOp("S..b8", "SIP To  : <sip:004972198765432@sipgate.de>") in new stack
-- Exec...4] NoOp("S..b8", "SIP PAI : ") in new stack
-- Exec...5] Set("S..b8", "FON=") in new stack
-- Exec...6] ExecIf("S..b8", "0?Set(CALLERID(num)=)") in new stack
-- Exec...7] NoOp("S..b8", "Caller-ID: "017112345678" <017112345678>") in new stack
-- Exec...8] ...

Exec…5: Patternmatching schlägt fehl, da der Header nicht gesetzt ist, somit is die Variable FON null.
Exec…6: 0? => Kondition nicht erfüllt => nichts tun
Exec…7: Verifizierung, dass die Nummer unverändert geblieben ist (vgl. Exec…1)

Die Endgräte zeigen nun immer die externe Rufnummer des Anrufers an. Somit kann der Anrufer bei einem verpassten Anruf auch zurückgerufen werden.

Viel Spass,

= C. | SaaS Web Techniklabor =

P.S.: Lustig ist, dass die App von Sipgate auch nur die interne ID anzeigt („Anruf von 12345e0“) und man verwirrt ist, wer nun wirklich anruft…