Thursday, January 31. 2008
Der neueste Hype ist Arc, ein Lisp-Dialekt. Und naja, was soll man dazu sagen? I went to a talk last summer by Guido van Rossum about Python, and he seemed to have spent most of the preceding year switching from one representation of characters to another. I never want to blow a year dealing with characters. Why did Guido have to? Because he had to think about compatibility. But though it seems benevolent to worry about breaking existing code, ultimately there's a cost: it means you spend a year dealing with character sets instead of making the language more powerful.
Which is why, incidentally, Arc only supports Ascii. Die allergrößte Mehrzahl aller natürlichen Sprachen lassen sich nicht mit dem Zeichensatz, den ASCII bietet, notieren. Damit schließt Paul Graham, der Autor von Arc, schon einmal von vornherein jegliche Lokalisierungs- und Internationalisierungsbemühungen aus. Wer Lisp verwenden will, der greife lieber zu CLisp, die denken nämlich an I18N/L10N. Lokalisierte Software für wachsende Zukunftsmärkte wie Indien oder China lässt sich mit Arc nämlich nicht entwickeln (naja, schon, aber wer will schon manuellen Lisp-Code für diverse Character Encodings schreiben?).
Enjoy your FAIL, Paul.
Dear Sam,
Although what you describe comes quite close to CI, it isn't. Unless you compile the code and run the test suite in a clean and neutral build environment, you can never be sure that the changes you're about to commit really do integrate properly. Even if you do a svn/cvs update (or the equivalent command of your favorite SCM) before you compile, run the tests and commit, you'll never know whether it compiles in other build environments. Perhaps you've forgotten to add a file to be committed, perhaps you've relied on certain specifics of your local system when tweaking something on the Makefiles. People make these mistakes all the time, and that's why we shouldn't rely on people running test suites locally.
That's what CI system like CruiseControl or Hudson are there for: they rebuild the software and run the test suite in a clean environment (ideally) whenever a commit is done, in continuous iterations, automatically, without any manual intervention by the programmer. With such simple little helpers combined with some notification, such integration mistakes or any other regressions that can be caught with the existing test suite wouldn't go unnoticed. Hey, you could even send notification emails about build and/or test failures (including their recoveries) to a public mailing list, which would dramatically increase the visibility of such automatized efforts.
If you already do so, I apologize for my possibly rude tone, but your article suggests that you don't.
Monday, January 28. 2008
David Tanzer recently blogged about comparing performance of equivalent C and C++ programs. He did so in order to be able to decide which of the two languages he should use as implementation language for his diploma thesis. In C, he used a classical dispatching mechanism, while in C++, he used inheritance and virtual methods. His result was that C++ was about 7 times slower with his test program. I couldn't believe this, and so I conducted my own tests, with a slightly modified source which can be downloaded here. I conducted tests of binaries with different optimization levels, all done with gcc/g++ 4.2.3 as provided by Debian unstable: Optimization | C (average of 3 runs; [s]) | C++ (average of 3 runs; [s]) |
---|
-Os | 38.778 | 34.001 | -O3 | 27.951 | 32.722 | -O2 -fomit-frame-pointer | 27.985 | 31.562 | -O0 | 33.271 | 34.192 |
Fast 3,5 Jahre ist es her, dass ich einen Patch für htpasswd, Teil des Apache httpd, submitted habe. Jetzt habe ich endlich Feedback erhalten, und trotzdem bin ich mir nicht mal sicher, ob die Intention meines Patches überhaupt verstanden wurde. Weiß zufällig jemand, ob bei Apache gerade eine Bug Triage o.ä. läuft, das dieses Feedback nach so langer Zeit erklären könnte?
Thursday, January 24. 2008
Ich wurde heute abend in der Linzer Straßenbahn von einer Kontrolleurin mit deutlich sächselndem Dialekt kontrolliert ("Tach, die Fahrscheine bitte!"). Willkommen, Gastarbeiter aus Deutschland! Wie arm muss es euch gehen, wenn ihr so einen Unterschichtenberuf (und wer die Linzer Kontrolleure kennt, weiß, was ich meine) im Ausland annehmt?
Wednesday, January 23. 2008
...als Beispiel für schlechten Code (das hier ist aus local-fetch.c): static const char *path; /* ... */ char filename[PATH_MAX]; strcpy(filename, path); strcat(filename, "/objects/pack/pack-"); strcat(filename, sha1_to_hex(sha1)); strcat(filename, ".idx"); /* ... */ int main(int argc, const char **argv) { /* ... */ path = argv[arg];
Warum muss ich bloß ca. 5 Sekunden grep(1)en, um ein ideales Codebeispiel zu finden, wie man mit Strings, Pfaden und User Input nicht umgeht in C?
Update: weil gefragt wurde, wie's richtig geht, hier noch die Auflösung: char filename[PATH_MAX]; snprintf(filename, sizeof(filename), "%s/objects/pack/pack-%s.idx", path, sha1_to_hex(sha1));
Das ist nicht nur sicherer, sondern auch kompakter und lesbarer. Nein, ich werde keinen Patch submitten.
Thursday, January 10. 2008
(This time in English, to make this article referencable to a broader audience)
Some of you may be aware of the technique of banner grabbing to find out what software is running on a remote machine. It is done by reading out transmitted data that contains a product name and/or version, such as HTTP's "Server:" response header. Like virtually every content sent by a server, the server is totally free what to send, i.e. this can be easily faked by an HTTP server's admin, and is sometimes even done.
Of course: faking Server headers won't protect you from the instant pwnage success of automated malware, in case your HTTP server software is vulnerable. Nevertheless, there are some people out there who think that masking the Server header would prevent any attacks (and they even try to make money with that assumption).
Banner grabbing is definitely the easiest way of trying to fingerprint an HTTP server, and the one that is easiest to defeat. In this article I will describe some simple techniques that I came up with that make HTTP fingerprinting much more reliable, and don't depend upon the value of any header (BTW, I am aware of httprint and their pretty good paper on the same subject, but I got aware of it after I already had a simple and working prototype of my ideas).
Fingerprinting in real life (as seen in CSI et al) usually concentrates on identifying unique features of a fingerprint, and matching it with other fingerprinting samples. So, what can be used as the fingerprint of an HTTP server? Whatever it returns to an HTTP client. Of course, not everything, the content of a requested resource is totally irrelevant for our case. So, what else is there? The response code (you know, HTTP/1.1 200 OK) and the headers.
When we have a look at the response code, it is pretty obvious that some HTTP server won't be easily distinguishable from another HTTP server through the answer of a regular GET request of an existing file (except for software such as gatling that returns "200 Coming Up" instead of the usual "200 OK"). But what we can do is to try out irregular or unusual HTTP requests. I tried out three different features: - Unusual request method (DELETE / HTTP/1.1)
- Illegal protocol name (HEAD / ABCD/1.1)
- Illegal protocol version (HEAD / HTTP/3.0)
. I tried out how different servers react on such requests, and the result was really astonishing: it was really hard to find two different HTTP servers that behaved in the same way for all 3 requests! (now I have a file with server signatures, and of the 27 fingerprints that I collected so far, there exist 23 unique response code triplets)
Such a quick achievement was really beyond my expectations, but soon I found out that there does exist some software that behaves almost the same. One such situation was thttpd and publicfile, and Apache-Coyote (the HTTP/1.1 server stack of Apache Tomcat)and lighttpd 1.5.0. So I was in need of a second feature. I had already used the response code, so what was left were the headers. But I wasn't really interested in the headers themselves, but more in the order of the headers. I quickly checked a few HTTP servers, and it soon showed that this would be promising.
So I added the order of the header names to the fingerprint of an HTTP server. As qualified headers I used virtually all headers, except for "Location", "Set-Cookie" and all "X-" headers: all of them are related to local configuration and/or applications, and have nothing to do with the HTTP server per se. Of course, not every server will return exactly the same set of headers in exactly the same order, I knew that there would be deviations. So I came up with a simple algorithm to determine the similarity of two fingerprints:
Let's say I have an existing fingerprint of a known HTTP server, and a recently retrieved fingerprint of a yet-to-be-identified HTTP server. My algorithm takes the first of the expected headers, and searches for it in the actual header at the first headers. If the header can't be found, I'll search for the next expected header, starting from the same position. If the header can be found, I go the next actual header, and start searching from there for the next expected header. If it can't be found, I continue with the next expected header, otherwise I move forward to the next actual header, and continue searching from there, and so on, until I'm finished with either the expected or actual headers. For every expected header that was found in the actual headers, I increment a counter. When I'm done, the similarity between expected and actual headers is counter / number of expected headers, i.e. a real number in the interval [ 0.0, 1.0 ].
The last step was to combine this with the response-code-based fingerprinting technique developed previously: a similarity factor between expected and actual response codes is computed by counting the number of response codes that match. As before, the similarity is counter / number of compared response codes (currently, the number of compared response codes is 3). This has the advantage that deviant response codes (e.g. through local configuration) still produce a reasonable similarity factor (.e.g if an HTTP server is configured to return a 302 redirect when a DELETE / is encountered, but the other 2 response codes are the same, the similarity factor is still at 2/3).
The final step to get an ultimate similarity factor is to compute the arithmetic mean of all similarity factors (i.e. (a + b) / 2). This procedure is applied to all available fingerprints. The fingerprints are then sorted in descending order by their similarity factor, and all fingerprints above a certain threshold (0.8 brought good results in my experiments) are selected as fingerprints that match very likely. If no such fingerprint could be found, the threshold is lowered by 0.1 until a fingerprint is found.
If you're interested in a proof-of-concept implementation of the technique that I described here, just have a look at the my HTTP fingerprinting tool with the working title " dactylizer" (a combination of dactyloscopy and analyzer), which even includes a pretty usable signature file with fingerprints for 27 different HTTP servers. Here's a sample session:
span style="color: #666666; font-style: italic;"># according to Server header: Apache # according to Server header: lighttpd/1.4.13
The find-match.rb matches an HTTP server's fingerprint with the list of existing fingerprints, while the pbaf.rb ("powder, brush, adhesive foil") script prints out a string that can be cut and pasted into the signature file. As you can see in this session, the fingerprinting doesn't work perfectly (at least when checking fun.drno.de), but it has the correct guess as #2 of 3 entries that it presents to the user.
A few interesting notes about stuff that I found while experimenting a bit with these tools during development: IBM HTTP Server sends an "epKe-Alive" header. WTF?! As of 2008-01-10, 0:33 am, googling for "epke-alive" yields exactly 0 search results. This looks so NUXIesque, but isn't. What also amused me was when I tried to fingerprint the opentracker bittorrent tracker (I fingerprinted denis.stalker.h3q.com:6969), it returned "Fnord 1.10" with a similarity factor of 0.8. Fnord is an HTTP server written by Fefe, and opentracker gets its scalability from the libowfat library, also written by Fefe. As if my fingerprinting tool knew about the relationships of those two pieces of software.
Wednesday, January 2. 2008
Hmm, jetzt muss ich doch einfach über Silvester bloggen... also, 24C3 in Berlin war, ich hab bei nion übernachtet, und dort die meiste Zeit in der VIP-Lounge verbracht, produktiv gewesen, und dann noch Silvester gefeiert. Und zwar im Kriegsgebiet. Naja, es war zumindest annähernd so, wie man sich Krieg vorstellt. Laut, chaotisch, gefährlich. Schön war's, betrunken waren wir, aber immerhin hab ich's noch locker geschafft, meinen Flug zurück in die Heimat zu erwischen.
Sunday, November 25. 2007
Nach schätzungsweise 6 Jahren Pascal-Abstinenz hab ich letzten Freitag abend/nachmittag wieder ein paar Zeilen Pascal-Code geschrieben, um meine Kenntnisse wieder etwas aufzufrischen. Und nun bin ich erstaunt, wie schnell und produktiv man in Pascal vorankommt und produktiv sein kann. Wer den Code sehen will, der sehe ihn sich bitte hier an. Es handelt sich um eine Implementierung von RFC 569. So richtig sinnvoll ist der Code nicht (jeder noch so einfache Editor heutzutage hat 10mal mehr Funktionalität und Komfort), aber ein gute Aufgabe, um einen Nachmittag mit der Ausimplementierung zu füllen.
Übrigens, das meiner Erfahrung nach bessere freie Pascal-System ist Free Pascal. GNU Pascal ist im Gegensatz dazu etwas buggy (auch wenn darum workarounden kann), und generiert wesentlich größere Binaries als Free Pascal.
Sunday, November 18. 2007
Ich hab mir grad den Spaß gemacht, mit Google Translate das zu übersetzen, was Borland Japan über den SilkPerformer 2007 schreibt. Google Translate hat anscheinend die Eigenschaft, Wörter, die es nicht kennt, in ihrer Transkription in lateinischen Großbuchstaben auszugeben. Im Inhalt der verlinkten Seite war das besonders interessant, da offenbar einige englische Begriffe bzw. Eigennamen in japanischen Schriftzeichen niedergeschrieben wurde. Eine Auswahl der Wörter, die ich so gefunden habe, und meine, die Bedeutung erkannt zu haben: - Borland SHIRUKUPAFOMA 2007 (ボーランド・シルクパフォーマー 2007) - Borland SilkPerformer 2007
- TESUTOSORYUSHON (テストソリューション) - test solution
- YUZARAISENSUPAKKU (ユーザーライセンスパック) - user license pack
- KODOKABAREJJITSURU (コードカバレッジツール) - code coverage tool (das hab ich allerdings auf der Produktseite zu "Silk & Gauntlet" gefunden)
- ROKARIZESHONTESUTO (ローカリゼーションテスト) - localization test (von der SilkTest Produktseite)
- TESUTOKABAREJJI (テストカバレッジ) - test coverage (von der SilkCentral Test Manager Produktseite)
- SUKURIPUTOREKODA (スクリプトレコーダ) - script recorder
- WAKUFUROUIZADO (ワークフローウィザード) - workflow wizard
Sehr witzig.
Monday, November 12. 2007
Vor einiger Zeit hab ich zufällig Szene geschaut, und beim nicht sehr anspruchsvollen Quiz, wer denn bei der CD-Release-Party des PBH Club dabei war (wer den Bericht 1 min davor gesehen hat, wusste, dass dies Michael Gaissmaier, der Sänger von Heinz aus Wien war), mitgemacht. Eigentlich hatte ich darauf schon wieder vollkommen vergessen, doch heute fand ich einen eigenartigen Briefumschlag in meinem Briefkasten. Und tatsächlich: ich hab gewonnen, und zwar das aktuelle PBH-Club-Album. Sehr fein. Auch wenn ich finde, dass der PBH Club Kommerz-Sellouts sind.
Sunday, November 11. 2007
Inspiriert durch bestimmte Ideen, die DJB in seinem Paper "Some thoughts on security after ten years of qmail 1.0" formuliert hat, hab ich mich am Wochenende dran gemacht, ein neues Projekt zu starten, und zwar einen LDAP-Server. "Ja", werden sich manche denken, "der AK ist aber ein handfester Trottel, dabei gibt es ja schon OpenLDAP, Fedora Directory Server, OpenDS, tinyldap, und noch ein paar andere Implementierungen". Nun, ja, oberflächlich betrachtet stimmt das, mein Ziel ist allerdings ganz spezifisch, und zwar werde ich als Storage-Backend das Filesystem selbst verwenden. Dabei mache ich mir den Umstand zunutze, dass die Baumstruktur unter Unix (naja, eigentlich sind Verzeichnisstrukturen unter Unix ja DAGs, aber egal) der hierarchischen Struktur von LDAP sehr ähnlich ist.
Die Idee ist, einen Distinguished Name (DN) durch ein Verzeichnis zu repräsentieren, und die dazugehörenden Attribute durch Dateien, wobei der Dateiname den Attributsnamen codiert, und der Dateiinhalt den Attributswert repräsentiert. Die Vorteile liegen auf der Hand: einerseits lassen sich damit quasi alle Operationen auf der Hierarchie von LDAP fast 1:1 auf Datei- bzw. Verzeichnisoperationen abbilden (was auch die Komplexität der Implementierung stark verringern sollte), andererseits schiebe ich etliche Probleme des parallelen Zugriffs und des Caching von der Applikation hin zum Betriebssystem. Und nachdem pro LDAP-Session ein Prozess verantwortlich ist (ein simpler forkender Server also), sollte die Performance meiner LDAP-Server-Implementierung quasi nur von der Performance der Prozesserzeugung und der Performance des eingesetzten Dateisystems abhängig sein. Gleiches gilt für die Skalierbarkeit. Im wesentlichen geht es vorerst einmal darum, ungefähre Performancewerte zu erhalten, und eventuelle Bottlenecks identifizieren zu können. Bis dahin muss ich allerdings einmal das LDAP-Protokoll völlständig ausimplementieren. Bisher geht nämlich nur der Use-Case BindRequest -> AddRequest(s) -> UnbindRequest.
Wednesday, November 7. 2007
Monday, November 5. 2007
Weil ich gerade einen herzlich sinnlosen Patch für das newsbeuter-Makefile gekriegt hab, der pkg-config dazu einsetzt, diverse Libraries zu finden, hab ich im Issue Tracker gleich mal ordentlich gerantet. Und eigentlich sollte dieser pkg-config-Rant auch meinen werten Lesern hier nicht vorenthalten werden: Rejected.
(a) Mentioned libraries are installed in system-wide directories by definition.
(b) When a user is capable installing it outside of the usual system-wide directories, he's also capable of adapting the Makefile accordingly.
(c) IMHO, it's very unlikely that somebody installs the library somewhere outside of a system-wide directory, but then takes care that the according .pc files are installed when pkg-config is searching for it.
A great example for the utter failure of pkg-config is how it fails to work with libraries that are installed via Fink on Mac OS X. Fink installs all its software under /sw, which is definitely not one of the "usual" prefixes such as /usr and /usr/local. And of course, the pkg-config that is delivered with Mac OS X fails to find any of the .pc file that are installed under /sw. When using the pkg-config that is delivered with Fink, the .pc files that are installed under /usr aren't found. In theory, pkg-config is great, but in practise, it's absolutely awful and IMHO less reliable than not using any semi-magic auto-detection mechanism.
Additionally, it depends on glib2, and I'm not going to endorse the installation of a plethora of bloated software that is of no direct use to users of newsbeuter.
Sunday, November 4. 2007
Es ist immer wieder praktisch, die Code Coverage von Programmen bei automatischen und manuellen Tests zu bestimmen, um feststellen zu können, welche Codeteile getestet und welche nicht getestet sind. Die GNU-Lösung für Code Coverage ist GCOV, ein eher krudes Commandline-Tool. Mir persönlich ist das Tool bei weitem nicht mächtig genug, und so habe ich heute LCOV, ein Wrapper um GCOV, der nicht nur farblich ansprechende und übersichtliche Ausgaben zur Code Coverage generiert, sondern mit dem es auch möglich ist, die Code Coverage von verschiedenen Testläufen problemlos zu akkumulieren. Und zwar geht das so:
Zuerst compiled man das zu testende Programm mit den CFLAGS (bzw. CXXFLAGS) "-fprofile-arcs -ftest-coverage". Dann lässt man das Programm laufen, und führt seine Tests durch (z.B. typische Use-Cases, oder aber auch ausprobieren aller vorhandenen Features, oder ...), und am Ende sammelt man die von GCOV geschriebenen Ergebnisse mit "lcov -d . -b . -o programm.info". Dann kann man einen weiteren Testlauf starten, z.B. Unit-Tests, oder einen anderen Use-Case, und mit einem weiteren Aufruf von "lcov -d . -b . -o programm.info" wird die Coverage dieses Testlaufs gesammelt. Wenn man dann alle Testläufe abgeschlossen hat, kann man aus dern Datei programm.info, welche die akkumulierte Code Coverage des getesteten Programms enthält, schöne übersichtliche Charts generieren, und zwar mit "genhtml programm.info". Man kann auch nach jedem Testlauf und Sammeln der Ergebnisse die HTML-Files generieren, um daraufhin für den nächsten Testlauf entscheiden zu können, welche Features noch genauer zu testen sind, usw. usf. Auf jeden Fall ist LCOV meiner heutigen Erfahrung nach wesentlich übersichtlicher und angenehmer, als GCOV per Hand zu bedienen.
|