Mehr Kontrolle bei externen Plugins

28. Dezember 2011 sep Keine Kommentare

Ich habe mich nun in letzter Zeit ein bisschen mit dem Schutz vor externen Plugins beschäftigt. Damit meine ich solche Plugins wie reCaptcha, bzw Like, +1 usw. Buttons. Die Lösung, welche Heise[1] vorgestellt hat, finde ich eigentlich sehr gut. Denn Bevor der Nutzer nicht einwilligt, werden keine Daten an den Dienst dahinter gesendet. Vorbildlich!

Nun hatte ich ein kleineres Web-Projekt. Dies umfasste auch ein kleines Kontaktformular. Da ich dies vor Spam-Angriffen mittels eines Captcha-Dienstes schützen wollte entschied ich mich relativ schnell für Googles reCaptcha. Nach einiger Zeit und einem besonderen Anlass habe ich mich dann über die Weitergabe der IP-Adresse belesen. Problem dabei ist es das es sich um einen Graubereich handelt. Es gibt Gerichtsurteile[2] dazu. Jedoch sind das nur kleinere Gerichte. Also, gehe ich lieber auf Nummer sicher und habe da ein kleines Script geschrieben.

So, nun aber erst einmal zu den Vorüberlegungen. Also,  zum einen muss ich das JavaScript für Google dynamisch nachladen. Dies darf aber erst geschehen, wenn der Benutzer eingewilligt hat. Hat er das nicht, darf keine Verbindung zu dem externen Plugin (reCaptcha) aufgebaut werden. Da nicht jeder Benutzer JavaScript im Browser aktiviert hat, sollte es aber trotzdem auch für diese funktionieren. Die Aufklärung der Benutzer muss also vor(!) Gebrauch des Plugins zugestimmt haben.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
        "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<title>Disclaimer</title>
	</head>
<body>
	<h1>Besondere Datenschutzbestimmungen</h1>
	<object data="./disclaimer.html" type="text/html" width="100%" height="350px" style="margin-top: 5px; border: #C8C8C8 solid 1px; border-right: #FFFFFF none 1px;">
		<p>Ihr Browser kann die besonderen Datenschutzbedingungen leider nicht anzeigen.</p>
		<p>Bitte öffnen Sie dieses Dokument: <a href="./disclaimer.html">Besondere Datenschutzbestimmungen</a></p>
	</object>
	<p style="text-align: center"><a href="./index.html">nicht akzeptieren</a>&nbsp;<a href="./form.html">akzeptieren</a></p>

	<script type="text/javascript" src="./js/jquery.min.js"></script>
	<script type="text/javascript">
		/* <![CDATA[ */
		$( document ).ready( function() {
			window.location.href = "./form.html";
		} );
		/* ]]> */
	</script>
</body>
</html>

Via der disclaimer.html wird dann der Text der Datenschutzbedingungen angezeigt (Welche Daten werden übermittelt und welche Bedingungen gelten).  Weiterhin habe ich eine kleine JS-Weiterleitung eingerichtet. Ist also JS aktiviert, wird gleich weiter geleitet und der User muss auf der nächsten Seite die Datenweitergabe bestätigen. Das können wir uns nun anschauen:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
        "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<title>Formular</title>
		<link rel="stylesheet" type="text/css" href="./colorbox.css">
	</head>
<body>
	<form enctype="multipart/form-data" action="http://tools.seplog.org/src/modules/MailForm.php" method="post">
		<table style="width: 500px; margin-left: -10px">
			<tr id="check" style="display: none">
				<td>&nbsp;</td>
				<td>
					<div style="float: left; padding-right: 5px; vertical-align: top;"><input type="checkbox" name="accept" style="padding: 2px;" tabindex="6"></div>
					<div id="cbcaptcha"><a class="inline" href="#inline_content">Datenschutzbestimmungen</a> akzeptieren.<span style="font-size: 8pt; vertical-align: bottom"><a href="#note" style="text-decoration: none">*</a></span></div>
					<div style="clear: left;"></div>
				</td>
			</tr>
			<tr id="trCaptcha">
				<td></td>
				<td>
					<div style="margin: 0px -6px" id="captcha">
						<noscript>
							<p><object data="https://www.google.com/recaptcha/api/noscript?k=6LcyfMgSAAAAAM_bDsCdDD2si3Q9oq5KCtSxShFz" type="text/html" height="300px" width="320px"></object></p>
							<p><textarea name="recaptcha_challenge_field" style="width: 295px; height: 100px" rows="5" cols="46" tabindex="14"></textarea></p>
							<p><input type="hidden" name="recaptcha_response_field" value="manual_challenge"></p>
						</noscript>
					</div>
				</td>
			</tr>
			<tr>
				<td></td>
				<td><input class="button" type="submit" name="submit" value="Absenden" tabindex="15"><input class="button" type="reset" name="reset" value="Zur&uuml;cksetzen" tabindex="16" style="margin-left: 5px"></td>
			</tr>
		</table>
	</form>
	<div style='display:none'>
		<div id='inline_content' style='padding:10px; background:#fff;'>
			<h1>Besondere Datenschutzbestimmungen</h1>
			<object data="./disclaimer.html" type="text/html" width="100%" height="300px" style="margin-top: 5px; border: #C8C8C8 solid 1px; border-right: #FFFFFF none 1px;">
				<p>Ihr Browser kann die besonderen Datenschutzbedingungen leider nicht anzeigen.</p>
				<p>Bitte öffnen Sie dieses Dokument: <a href="./disclaimer.html">Besondere Datenschutzbestimmungen</a></p>
			</object>
			<p style="text-align: center"><a href="./index.html">nicht akzeptieren</a>&nbsp;<a id="acceptLabel" href="#">akzeptieren</a></p>
		</div>
	</div>

	<script type="text/javascript" src="./js/jquery.min.js"></script>
	<script type="text/javascript" src="./js/jquery.colorbox-min.js"></script>
	<script type="text/javascript" src="./js/script.js"></script>

</body>
</html>

Wie wir hier sehen ist die checkbox normalerweise nicht sichtbar. Diese wird erst durch das JavaScript angezeigt. Denn wenn ein User JS nicht aktiviert hat, hatte er den Datenschutzbestimmungen ja schon zugestimmt. Ebenso ist nur der noscript-Block vom reCaptcha  enthalten. Dies wird also auch nur ausgeführt wenn JS nicht aktiv ist. Der Rest geschieht nacher in der Script.js Datei. Dort wird das reCaptcha Plugin dynamisch nachgeladen, sobald der Haken für die Datenschutzbestimmungen aktiviert wird.

Das ganze JavaScript schaut dann so aus:

var loadReCaptcha = false;

function activateRecaptcha( show ) {
	if( loadReCaptcha === false && show === true ) {
		$( '#captcha' ).append( "Plugin reCaptcha wird geladen..." );
		$.getScript( "https://www.google.com/recaptcha/api/js/recaptcha_ajax.js", function() {
			Recaptcha.create( "public_key", "captcha", {
				theme: "white",
				lang: "de",
				callback: Recaptcha.focus_response_field
			} );
		} );
		loadReCaptcha = true;
	}

	if( show ) {
		$( '#trCaptcha' ).show();
	}
	else {
		$( '#trCaptcha' ).hide();
	}
}

$( document ).ready( function() {

	$( '#check' ).show();
	$( '#trCaptcha' ).hide();

	if( $( 'input[name=\'accept\']' ).is( ':checked' ) === true
	    && $( '#trCaptcha' ).is( ':visible' ) === false	) {
		activateRecaptcha( true );
	}

	$( 'form' ).submit( function() {
		if( $( 'input[name=\'accept\']' ).is( ':checked' ) === false ) {
			alert( "Sie müssen die Datenschutzbestimmungen akzeptieren!" );
			return false;
		}
	} );

	$( 'input[name=\'accept\']' ).change( function() {
		activateRecaptcha( $( 'input[name=\'accept\']' ).is( ':checked' ) === true );
	} );

	$( '.inline' ).colorbox( { inline: true, width: "650px", height: "500px" } );
	$( '#acceptLabel' ).click( function() {
		$( '.inline' ).colorbox.close();
		if( $( 'input[name=\'accept\']' ).is( ':checked' ) === false ) {
			$( 'input[name=\'accept\']' ).attr( 'checked', true );
			activateRecaptcha( true );
		}
	} );

} );

So bin ich nun erst einmal aus dem Schneider. Die Weiterreichung der IP-Adressen, Referer und eines Zeitstempels geschieht erst nach der Einwilligung des Benutzers. Für alle Benutzer welche den Dienst nicht in Anspruch nehmen entsteht somit auch kein Nachteil. Ein kleineres Problem gibt es nur noch zur Zeit. Ich rufe das reCaptcha-JavaScript per https auf. Jedoch werden die anderen JS-Dateien welche das Plugin nachlädt ganz normal via http übertragen. Ist eigentlich nicht so schön. Aber erst einmal funktioniert alles so.

Links

  1. 2 Klicks für mehr Datenschutz
  2. Speicherung einer dynamische IP-Adresse bei Nutzung eines Internet-Portals

PGP Schlüssel erneuert

12. November 2011 sep Keine Kommentare

Hey, nach längerer Zeit mal wieder was von mir. Aber nur was allgemeines. Mein aktuellen PGP-Schlüssel ist bald abgelaufen. Um diesem vorzubeugen habe ich gerade einen neuen Schlüssel zur Verfügung gestellt. Dieser ist auf meiner Kontaktseite zu finden. Die weitere Kommunikation via E-Mail wird dann nur noch über den neuen Schlüssel laufen.

Categories: Allgemeines Tags:

Der Stack

24. Mai 2011 sep Keine Kommentare

Ich habe mich in letzter Zeit ein wenig mit der Erstellung von Maschinencode und dem Stack beschäftigt. Dies hatte verschiedene Gründe. Zum Einen schreibe ich gerade an einem Simulator für AVR-Geräte, welcher natürlich Maschinencode ausführen soll und zum Anderen wollte ich einfach mal rein schauen und ein bisschen schlauer werden.
Wie dem auch sei. Ich bin dabei auf etwas Interessantes gestoßen. Wenn eine Funktion den Stack für die lokalen Variablen anlegt, so wird der Stack-Pointer immer wieder nach einem Wert ausgerichtet. Normalerweise handelt es sich dabei um den Wert 16. Dies geschieht bei dem anlegen von normalen lokalen Variablen, genauso wie dem definieren von variablen Arrays und auch von dem allozieren des Hauptspeichers auf dem Stack. Dazu möchte ich nun ein paar kleine, einfache Beispiele anbringen. Diese werden dann übersetzt und die de‑assemblierte Datei wird dann untersucht.
Zu dem Programmcode an sich. Natürlich soll dies kein Programm in einer produktiven Umgebung sein. Es dient nur zu Demonstrationszwecken. Weiterhin nutze ich den gcc in der folgenden Version:

$ gcc --version
gcc (Gentoo 4.4.5 p1.2, pie-0.4.5) 4.4.5
Copyright (C) 2010 Free Software Foundation, Inc.
Dies ist freie Software; die Kopierbedingungen stehen in den Quellen. Es gibt KEINE Garantie; auch nicht für MARKTGÄNGIGKEIT oder FÜR SPEZIELLE ZWECKE.

Nun also habe ich mir ein kleines Programm erstellt, welches in einer Funktion eine feste Puffergröße hat. Diese Puffergröße wird zu Compilezeit definiert.

#include <stdlib.h>
#include <string.h>

#if !defined( SIZE ) || SIZE <= 0
#define SIZE 1
#endif

void foo( void ) {

        char buffer[ SIZE ];
        strncpy( buffer, "AAAAAAAAAAAAAAAA", SIZE );
        buffer[ ( SIZE - 1 ) ] = 0;

}

int main( void ) {

        foo();
        return EXIT_SUCCESS;

}

Ich werde nun erst einmal erklären wo der Stack für die lokalen Variablen eingerichtet wird. Danach werde ich eine Tabelle erstellen wo sichtbar ist, wie die Größe des Stacks durch die Größe des Puffers beeinflusst wird.
Zuerst wird das Programm kompiliert. Danach schauen wir uns den erzeugten Maschinencode an.

$ gcc -DSIZE=2 stack.c -o stack
$ objdump -d stack
[…]
0000000000400534 <foo>:
400534:       55                      push   %rbp
400535:       48 89 e5                mov    %rsp,%rbp
400538:       48 83 ec 10             sub    $0x10,%rsp
40053c:       b9 5c 06 40 00          mov    $0x40065c,%ecx
400541:       48 8d 45 f0             lea    -0x10(%rbp),%rax
400545:       ba 02 00 00 00          mov    $0x2,%edx
40054a:       48 89 ce                mov    %rcx,%rsi
40054d:       48 89 c7                mov    %rax,%rdi
400550:       e8 eb fe ff ff          callq  400440 <memcpy@plt>
400555:       c6 45 f1 00             movb   $0x0,-0xf(%rbp)
400559:       c9                      leaveq
40055a:       c3                      retq
[…]

Am Anfang dieser Funktion befindet sich der Funktionsprolog[1]. Der Stackframe wird eingerichtet. Dies ist unabdingbar, da bei dem Ende der Funktion garantiert werden muss das vom Stack alle Variablen wieder gelöscht werden.

  1. Alter StackFrame
  2. Rücksprungadresse
  3. BasePointer wird gesichert (Anfang des alten StackFrames)
  4. Der aktuelle StackPointer ist der Anfang des Aktuellen StackFrame

So schaut der aktuelle Stack aus wenn das Programm bis zur Speichernummer 0×400535 ausgeführt wird. Danach werden die lokalen Variablen eingerichtet. Am Ende übernimmt das „leave“ wieder die Aufräumarbeiten. Somit ist leave ein Synonym für[2]:

mov    %rbp,%rsp
pop    %rbp

Damit wird der alte StackFrame wieder eingerichtet und mit return wird dann die Rücksprungadresse von dem Stack gelesen. Somit ist der Stack wieder aufgeräumt.
Weiterhin werden an Speicherstelle 0×400538 die lokalen Variablen alloziert. Wie man sieht werden hier 0×10 also 16 Byte an Variablen reserviert. Ich habe aber als Größe 2 angegeben. Da es sich um char handelt also 2 Byte. Ich möchte nun eine Tabelle erstellen. Diese Zeigt jeweils die Größe welche ich reservieren möchte und die tatsächlich reservierte Größe an.

SIZE (in Byte)    Stack SIZE(in Byte)
2                      16
3                      16
5                       16
16                     16
17                     32
18                     32
31                     32
32                     32
33                     48
8192                 8192
8193                 8208

Wie hier zu sehen ist, handelt es sich jeweils um einen Teiler von 16. Ähnlich verhält es sich bei der Verwendung von alloca, welches Speicherplatz auf dem Stack reserviert. Dies bedeutet der Gültigkeitsbereich der Variablen endet mit Austritt aus der Funktion. Wie bei einer normalen lokalen Variablen. Nur ist die Größe der Variablen dynamisch. Das bringt ab und an ein paar kleine Vorteile. Denn man muss den Speicherplatz nicht wieder mit free frei räumen.
Nun zu dem Beispiel:

#include <stdlib.h>
#include <string.h>

#if !defined( SIZE ) || SIZE <= 0
#define SIZE 1
#endif

void foo( int i ) {

        char* buffer = NULL;
        buffer = alloca( i );

        if( NULL != buffer ) {

                strncpy( buffer, "AAAAAAAAAAAAAAAA", SIZE );
                buffer[ ( i - 1 ) ] = 0;

        }

}

int main( void ) {

        foo( SIZE );
        return EXIT_SUCCESS;

}

Im Prinzip der gleiche Code. Nur erfolgt die Zuweisung des Speichers mit alloca und ich gebe die Größe des Puffers als Parameter an. Ich übersetze dies und schau mir wieder die de-assemblierte Datei an.

$ gcc stack.c -o stack -DSIZE=2
$ objdump -d stack
[…]
0000000000400534 <foo>:
400534:       55                      push   %rbp
400535:       48 89 e5                mov    %rsp,%rbp
400538:       48 83 ec 20             sub    $0x20,%rsp
40053c:       89 7d ec                mov    %edi,-0x14(%rbp)
40053f:       48 c7 45 f8 00 00 00    movq   $0x0,-0x8(%rbp)
400546:       00
400547:       8b 45 ec                mov    -0x14(%rbp),%eax
40054a:       48 98                   cltq
40054c:       48 83 c0 0f             add    $0xf,%rax
400550:       48 83 c0 0f             add    $0xf,%rax
400554:       48 c1 e8 04             shr    $0x4,%rax
400558:       48 c1 e0 04             shl    $0x4,%rax
40055c:       48 29 c4                sub    %rax,%rsp
40055f:       48 89 e0                mov    %rsp,%rax
400562:       48 83 c0 0f             add    $0xf,%rax
400566:       48 c1 e8 04             shr    $0x4,%rax
40056a:       48 c1 e0 04             shl    $0x4,%rax
40056e:       48 89 45 f8             mov    %rax,-0x8(%rbp)
400572:       48 83 7d f8 00          cmpq   $0x0,-0x8(%rbp)
400577:       74 29                   je     4005a2 <foo+0x6e>
400579:       b9 ac 06 40 00          mov    $0x4006ac,%ecx
40057e:       48 8b 45 f8             mov    -0x8(%rbp),%rax
400582:       ba 1f 00 00 00          mov    $0x1f,%edx
400587:       48 89 ce                mov    %rcx,%rsi
40058a:       48 89 c7                mov    %rax,%rdi
40058d:       e8 ae fe ff ff          callq  400440 <strncpy@plt>
400592:       8b 45 ec                mov    -0x14(%rbp),%eax
400595:       48 98                   cltq
400597:       48 83 e8 01             sub    $0x1,%rax
40059b:       48 03 45 f8             add    -0x8(%rbp),%rax
40059f:       c6 00 00                movb   $0x0,(%rax)
4005a2:       c9                      leaveq
4005a3:       c3                      retq
[…]

Der Funktionsprolog ist wieder vorhanden und in 0×400538 und 0×40053F wird der Zeiger eingerichtet. Die Zeile 0×40053C lädt den Parameter i nach EDI. Nachzulesen ist dies bei Calling Conventions cdecl[3]. Zu beachten ist dabei immer der Stack und der Anfang des StackFrames. Dieser liegt ja in dem BasePointer.
Nun wird in Zeile 0×400547 nochmals der Parameter nach EAX geladen. CLTQ wird zur Synchronisation genutzt. (Das stimmt ja so nicht. Wie ich nu gelesen hab wird es genutzt um eax in ein QuadWord zu konvertieren. Also nach rax!) Weiterhin wird nun der Parameter vorbereitet. Folgende Rechnung:

( ( 0×02 + 0×0F + 0×0F ) >> 0×04 ) << 0x04 = 0x20

Laut[4] werden Stellen die bei einem Shift frei werden mit 0 aufgefüllt. Dies passiert alles von 0×40054C bis 0×400558. Danach wird das Ergebnis mit dem aktuellen StackPointer verrechnet und den trifft dann das gleiche Schicksal. Also haben wir wieder mehr Speicher reserviert als wir brauchen. Nämlich haben alle einen gemeinsamen Teiler. Der ist 16.
Woher kommt das also. Ich bin bei der Suche dort auf einige interessante Sachen gestoßen. Meine erste Idee war es Fragmentierung zu vermeiden[5]. Jedoch habe ich diese Idee wieder verworfen. Denn es handelt sich hierbei um den Stack. Dieser wird nachdem die Funktion abgearbeitet wurde wieder frei geräumt. Weiterhin denke ich das Vorsorge zur Fragmentierung ein bisschen anders ausschaut. Da müsste ich ggf. mal in den Quellcode von malloc schauen. Dann finde ich da vielleicht auch was dazu.
Eine andere Idee hatte ich gefunden als ich mich mit den Anfängen der Speicherverwaltung beschäftigt habe. Dort bin ich dann auf die Speichersegmentierung der 80×86 Prozessoren gestoßen. Denn als es noch 16Bit Prozessoren gab wollte man doch mehr als 64KiB Speicher haben. Also hatte man eine Adressbreite von 20Bit. Die Speicheradresse wurde dann mit Segment und Offset berechnet. Das ist alles hier[6] ganz schön beschrieben. So lautet auch ein Absatz

Durch die Multiplikation mit 16 hat sich auch die kleinste, durch die Segmentadresse adressierbare Einheit verändert. Sie beträgt nun nicht mehr 1 Byte, sondern insgesamt 16 Byte. Diese 16 Byte werden in diesem Zusammenhang auch als “Paragraph” bezeichnet.

Damit war ich dann die erste Zeit zufrieden. Nach einiger Zeit habe ich mir dann so gedacht, nein das kann ja kein Relikt aus den alten Zeiten sein und machte mich von neuem auf die Suche.
Dann fand ich einen ersten Hinweis. Dabei handelt es sich um einen Schalter vom gcc namens „-mpreferred-stack-boundary=num“[7].
Gibt man diesen beim kompilieren mit an, so verändert sich der „Teiler“. Erst einmal zu der Dokumentation. Der Wert von preferred-stack-boundary muss zwischen 4 und 12 liegen. Berechnet wird dies dann 2num. Also mit dem std Wert 24 usw usf. Also wenn ich mir nun noch mal das erste Beispiel anschaue und dies nochmal mit der Option -mpreferred-stack-boundary übersetze und mit dieser Option spiele ergibt sich folgendes.

Preferred-stack-boundary    SIZE (in Byte)    Stack SIZE (in Byte)
4                                     2                      16
5                                     2                      48
6                                     2                      112
12                                   2                      8176

Also habe ich dort nun eine Möglichkeit dies zu bearbeiten. Weiterhin fand ich heraus wozu dies gut sein sollte. Denn dies steht ebenso in der Dokumentation unter „-mincoming-stack-boundary“. Einzig und allein für die Streaming SIMD Extentions ist dies von Vorteil. Denn diese haben eine Wortbreite von 128Bit → 16Byte. Wenn nun also SSE in dem Programm genutzt wird, kann einfacher und schneller auf den Stack zugegriffen werden. Es muss nicht darauf geachtet werden die Variablen erst zu „normalisieren“, sondern sie können direkt in den Speicher geladen und genutzt werden.
Leider habe ich nun noch nicht so viel Erfahrung im Bereich SSE. Jedoch gebe ich mich mit dieser Art der Antwort nun endlich zufrieden. Hier[8] hat man auch eine ganz gute Einführung in das Thema. Jedoch werde ich mir dies später mal anschauen.
Ich bin nun froh, das ich doch wieder einiges dazu gelernt habe. Weiterhin ist zu sagen dass ich dies nur auf den GCC hin untersucht habe. Wie sich das bei anderen Compilern verhält weiß ich nicht.

Quellen

  1. Function prologue
  2. Enter / Leave
  3. Aufrufkonventionen
  4. Intel Architecture Software Developer’s Manual Volume 2: Instruction Set Reference
    S. 663 (SAL/SAR/SHL/SHR—Shift (Continued))
  5. Heap-Fragmentierung
  6. Logische Adressierung / Segmentierung
  7. Intel 386 and AMD x86-64 Options (-mpreferred-stack-boundary)
  8. HowTo: Inline Assembly & SSE: Vector normalization done fast!
Categories: Informatik Tags: , , ,

Mehr IP-Adressen für die Fritz!Box

10. März 2011 sep Keine Kommentare

Ich besitze eine kleine Fritz!Box Fon WLAN 7113 und fange langsam an das kleine Ding zu lieben. Damit wollte ich mir ein kleines Netzwerk aufbauen. Mit einer kleinen “Serverfarm”, einem LAN-Bereich und natürlich WLAN. Dabei sollen diese drei Bereiche auch in drei unterschiedlichen Netzen liegen. Alle sollen dann auch mit dem Internet kommunizieren können. Wäre da nicht nur das Problem, dass die Fritz!Box nur über eine LAN Schnittstelle verfügt. Somit kann die Box nur in einem Netz vorhanden sein. Also wollte ich mir dann einen zweiten Router kaufen, welcher mit mehreren Netzen kommunizieren kann.
Aber nun weiß ich, die Fritz!Box kann das auch!

Dazu habe ich mir zufälligerweise mal die export-Datei angeschaut. Dort habe ich entdeckt, dass auf eth0 (Also der LAN-Schnittstelle) noch eine zweite IP konfiguriert ist (169.254.1.1). Bei AVM heißt es diese Adresse ist nicht veränderbar und zur Sicherheit vorhanden. Unter “9.1 Fehler beim Öffnen der Benutzeroberfläche”[1] ist dort ein bisschen was zu finden. Nun stellte ich mir erstens die Frage, ob ich diese IP bearbeiten kann, oder ob ich einfach neue definieren kann. Dazu habe ich mir eine Sicherung von der Box geladen (Da hab ich aber nicht viel angefasst). Nun habe ich angefangen mich ein bisschen in die Datei einzulesen und bin auch schnell fündig geworden. In dem Abschnitt “ethinterfaces” und unter “brinterfaces” werden die IP-Adressen der Box definiert. Das sieht dann wie folgt aus.

ethinterfaces {
    name = "eth0";
    dhcp = no;
    ipaddr = 192.168.2.254;
    netmask = 255.255.255.0;
    dstipaddr = 0.0.0.0;
    dhcpenabled = yes;
    dhcpstart = 192.168.178.20;
    dhcpend = 192.168.178.200;
} {
    name = "eth0:0";
    dhcp = no;
    ipaddr = 169.254.1.1;
    netmask = 255.255.0.0;
    dstipaddr = 0.0.0.0;
    dhcpenabled = yes;
    dhcpstart = 0.0.0.0;
    dhcpend = 0.0.0.0;
}

brinterfaces {
    name = "lan";
    dhcp = no;
    ipaddr = 192.168.2.254;
    netmask = 255.255.255.0;
    dstipaddr = 0.0.0.0;
    interfaces = "eth0", "usbrndis", "tiwlan0", "wdsup0",
        "wdsdw0", "wdsdw1", "wdsdw2", "wdsdw3";
    dhcpenabled = yes;
    dhcpstart = 192.168.178.20;
    dhcpend = 192.168.178.200;
} {
    name = "lan:0";
    dhcp = no;
    ipaddr = 169.254.1.1;
    netmask = 255.255.0.0;
    dstipaddr = 0.0.0.0;
    dhcpenabled = yes;
    dhcpstart = 0.0.0.0;
    dhcpend = 0.0.0.0;
}

Da ich das System mit “eth0″ und “eth0:0″ usw von Linux her kenne[2], habe ich das einfach mal übernommen. So erstellte ich dort einen neuen Abschnitt (eth0:1/lan:1).

ethinterfaces {
    name = "eth0";
    dhcp = no;
    ipaddr = 192.168.2.254;
    netmask = 255.255.255.0;
    dstipaddr = 0.0.0.0;
    dhcpenabled = yes;
    dhcpstart = 192.168.178.20;
    dhcpend = 192.168.178.200;
} {
    name = "eth0:0";
    dhcp = no;
    ipaddr = 169.254.1.1;
    netmask = 255.255.0.0;
    dstipaddr = 0.0.0.0;
    dhcpenabled = yes;
    dhcpstart = 0.0.0.0;
    dhcpend = 0.0.0.0;
} {
    name = "eth0:1";
    dhcp = no;
    ipaddr = 192.168.2.253;
    netmask = 255.255.255.0;
    dstipaddr = 0.0.0.0;
    dhcpenabled = yes;
    dhcpstart = 0.0.0.0;
    dhcpend = 0.0.0.0;
}

brinterfaces {
    name = "lan";
    dhcp = no;
    ipaddr = 192.168.2.254;
    netmask = 255.255.255.0;
    dstipaddr = 0.0.0.0;
    interfaces = "eth0", "usbrndis", "tiwlan0", "wdsup0",
        "wdsdw0", "wdsdw1", "wdsdw2", "wdsdw3";
    dhcpenabled = yes;
    dhcpstart = 192.168.178.20;
    dhcpend = 192.168.178.200;
} {
    name = "lan:0";
    dhcp = no;
    ipaddr = 169.254.1.1;
    netmask = 255.255.0.0;
    dstipaddr = 0.0.0.0;
    dhcpenabled = yes;
    dhcpstart = 0.0.0.0;
    dhcpend = 0.0.0.0;
} {
    name = "lan:1";
    dhcp = no;
    ipaddr = 192.168.2.253;
    netmask = 255.255.255.0;
    dstipaddr = 0.0.0.0;
    dhcpenabled = yes;
    dhcpstart = 0.0.0.0;
    dhcpend = 0.0.0.0;
}

Dann versuchte ich dies einzuspielen, doch gab es dort Probleme mit der Checksumme. Glücklicherweise gibt es dort ein kleines Programm namens FBF Editor[3]. Damit muss man nicht mal mehr in die Web-Oberfläche. Also die bearbeitete Version eingespielt und BÄHM, hab ich auf der Box eine neue IP, worüber ich diese ansprechen kann. Ich muss die dann später, wenn ich mit meinem Netz weiter mache nur anders definieren, aber das ist ja nun kein Problem mehr. Also, viel Erfolg dabei! ;)

  1. Handbuch FRITZBox Fon WLAN 7170
  2. Linux – Wegweiser für Netzwerker
  3. FBF Editor
Categories: Informatik Tags: , , ,

Never touch a running system

19. September 2010 sep 2 Kommentare

Oder wie war das doch gleich?

Nachdem ich gestern Abend mal nach einem Monat ein emerge –sync ausgeführt hatte um mein System zu aktualisieren, hatte ich heute morgen die Bescherung. Ich konnte mich nicht mehr anmelden. Kurz zu meinem System. Ich habe für mein Gentoo 3 Partitionen. Eine als /boot, die andere als root und eine Weitere für /home. Die Home- und die Root-Partition sind verschlüsselt. Die Boot-Partition entschlüsselt diese beiden Partitionen um dann durchstarten zu können. Dies funktioniert mittels Luks und einem initrd.

Nachdem ich also gebootet habe, konnte meine Home-Partition nicht gemountet werden. Diese wurde zwar entschlüsselt, jedoch gab es kein Device-Node. Als ich nach 2h Suche nun doch nichts fand wandte ich mich ans IRC an den gentoo-channel. Dort wurde mir gesagt, dass der “device-mapper”  nun in LVM Einzug gehalten habe und dass ich meinen alten Kernel (2.6.29) mal erneuern sollte. Die gentoo-sources sind schließlich schon auf 2.6.34. Also tat ich das und bootete erst einmal neu. Nachdem das auch nicht den gewünschten Erfolg brachte wollte ich gerade aufgeben und fing schon an meine Daten zu kopieren um erst einmal unverschlüsselt fort zu setzen. Dann kam ich auf eine Idee.

Ich habe nun mal geschaut, wie dm-crypt mittels LVM arbeiten soll. Da hab ich aber dann zufälligerweise ein altes HowTo gefunden. Dies wollte noch den “device-mapper” haben. Sodann wollt ich das installieren und mir wurde gemeldet dass udev und lvm2 dies Paket blockieren. Verdammt! Dann kam mir kurz darauf die nächste dumme Idee. Wenn denn der device-mapper in LVM nun drin steckt, dann sollt ich doch da mal besser schauen. Natürlich hat LVM ein init-Script. Dies startete ich und auf ein mal waren dann dort auch die Device-Nodes…

Die Moral von der Geschichte? Never touch a running system! Es sei denn ihr habt ein Backup, Zeit oder Ahnung. Und für gentoo braucht man nun mal Zeit und auch ein bisschen Ahnung. Ich weiß nun zumindest das ich heute Abend noch ein Backup machen werde. Denn besonders wenn man wenig Zeit hat kann einem das doch ab und an mal helfen! ;)

Categories: Informatik Tags:

Programmierung und Speicherstrukturen

18. Juli 2010 sep Keine Kommentare

Da ich doch öfters schon mal feststellen musste, dass angehende Informatiker oder auch Informatiker recht wenig Wissen über Collections und Datensammlungen haben, möchte ich hier mal versuchen meine Erfahrungen mit Collections in der Programmiersprache Java kund zu tun. Denn die Informatik beschäftigt sich nun mal sehr stark mit der Haltung und auch der Auswertung von Datenmengen. Damit dies hochperformant gesehen kann, sollte man sich in den verschiedenen Arten der Datenstrukturen doch schon auskennen.

Was sind Collections?

Collections sind in der Programmierung Strukturen zum organisieren von Daten. Das heißt um Daten in dem Arbeitsspeicher zu halten, oder zu bearbeiten, oder oder oder. Möglichkeiten der Datennutzung gibt es ja viele. Genauso gibt es auch viele Strategien zum organisieren der Daten innerhalb der Collection. Jede Strategie hat natürlich ihre Vor- und Nachteile. Jedoch möchte man nach Möglichkeit nur die Vorteile nutzen, um ein Programm möglichst leistungsfähig umzusetzen. Einen guten Überblick über die verschiedenen Arten von Collections im Java-Framework gibt die Java-Dokumentation her[1]. Einzuteilen sind diese Strukturen in

  1. Array
  2. List
  3. Vector
  4. Queue
  5. Stack
  6. Set
  7. Map

Ich werde nun versuchen die einzelnen Arten der Datensammlungen anzureißen und einen Überblick über diese zu geben.

Array

Das Array oder auch Feld, ist in der Programmierung wohl eines der bekanntesten Vertreter der Datenstrukturen. Es zeichnet sich dadurch aus, dass es sehr kompakt ist. Die Zugriffe auf die einzelnen Elemente erfolgt direkt anhand eines Indexes. Somit gibt es sehr kurze Zugriffszeiten bei einem willkürlichen Zugriff. Im inneren ist ein Array ein fest reservierter, zusammenhängender Platz im Speicher. Die Elemente werden nacheinander in diesem reservierten Speicher abgelegt. Der Index, mit welchem auf die Elemente zugegriffen wird, bezeichnet dann den Abstand des Elements von dem Anfang des Arrays. Somit gibt es nur einen Verweis auf das erste Element und die Elemente selbst, welche in dem Array gespeichert werden.

List

Bei einer Liste handelt es sich um eine dynamisch wachsende Speicherstruktur. Einzelne Elemente oder auch mehrere sind wiederum mit einzelnen oder mehreren Elementen verkettet. Die Elemente liegen also nicht nacheinander im Speicher sondern können überall abgelegt werden. Das wichtige dabei ist jedoch, dass die Verweise nicht abhanden kommen. Der Vorteil liegt klar auf der Hand. Es können dynamisch Elemente hinzu gefügt werden. Die Liste besitzt also keine festen Grenzen wie Beispielsweise das Array. Jedoch habe ich keinen direkten willkürlichen Zugriff auf die Elemente. Denn um zu einem Element zu gelangen muss ich immer den Verweisen, bis zu dem gewünschten Element folgen. Somit ist eine Liste selbstverständlich langsamer als ein Array. Des Weiteren werden bei Listen häufig Statusinformationen vorgehalten. Wie die Kapazität der Liste, oder auch die Anzahl der Elemente, welche sich in einer Liste befinden. Außerdem muss Speicher für die Verweise auf Elemente zur Verfügung stehen. Somit ist noch ein Nachteil der Liste klar sichtbar. Der Overhead ist natürlich auch größer als bei einem Array. Es gibt sehr viele verschiedene Möglichkeiten eine Liste zu programmieren und man wird im Internet sehr schnell fündig über Herangehensweisen an eine Liste. So möchte ich auch eine aufzeigen, da ich vor einiger Zeit eine Liste in C implementiert habe. Dabei handelt es sich um eine einfach verkettete Liste[2].

Vector

Bei einem Vektor handelt es sich ebenfalls um eine dynamische Speicherstruktur. Jedoch wird hier versucht den Nachteil der Lesegeschwindigkeit zu kompensieren. Bei einem Vector handelt es sich im inneren um ein Array, welches nach Bedarf vergrößert wird. Ist also die Kapazität eines Vectors erschöpft, wird ein neues Array initialisiert und alle Elemente welche enthalten waren werden einfach in das neue Array kopiert. Somit hat sich die Kapazität vergrößert. Der Vorteil ist, dass es hier ebenfalls einen willkürlichen Zugriff gibt. Die Lesegeschwindigkeit ist ähnlich hoch, wie bei einem Array. Jedoch kann das Einfügen sehr viel länger dauern, wenn denn die Kapazität des Vektors vergrößert werden muss. Von daher sollte man ungefähr eine Ahnung haben wie viele Elemente in dieser Datensammlung gespeichert werden sollen.

Queue

Bei der Queue handelt es sich um eine Datensammlung nach dem FIFO-Prinzip. Also First-in-First-out. Der Zugriff auf die anderen Elemente ist nachrangig. Es erfolgt immer nur direkter Zugriff auf das erste Element in der Struktur. Inwieweit hier intern die Daten organisiert werden ist ebenfalls nachrangig. Da ein Element sofort wieder verworfen wird, wenn es gelesen wurde. Wo kann man eine solche Datenstruktur einsetzten? Ich würde unter anderem sagen, wo Daten aus einem Stream kommen. Es wird dann dort gearbeitet wie bei einer Warteschlange. Die Daten, welche als erstes aus einem Stream kommen, werden als erstes verarbeitet. Die anderen müssen sich hinten anstellen und auf die Verarbeitung noch warten.

Stack

Bei einem Stack handelt es sich um ein ähnliches Prinzip wie bei der Queue. Nur das ein Stack nach dem LIFO-Prinzip arbeitet (Last-in-First-out). Also genau anders herum. Mir mag leider gerade kein Beispiel einfallen, wo ein Stapelspeicher eingesetzt wird in der Programmierung. Jedoch wird auf Prozessorebene ein Stack eingesetzt. Wenn der Prozessor in ein Unterprogramm springt, also in eine Funktion, so wird mindestens die Rücksprungadresse auf den Stack geschrieben. Wenn die Funktion abgearbeitet ist, holt er sich die letzte Rücksprungadresse aus dem Speicher und setzt dann dort seine Arbeit wieder fort.

Set

Bei einem Set handelt es sich um eine Menge. Das heißt ein Element darf in dieser Datensammlung nur ein mal vorkommen. Jetzt stellt sich mir die Frage, wie man das möglichst effizient lösen möchte. Da half mir ein kleiner Blick in die Java-Sources (Die sollten bei einer SDK Installation dabei sein). Jedes Objekt kann in der OOP einen so genannten HashCode erzeugen. Dieser HashCode ist relativ eindeutig.

Ein Hashwert wird deshalb auch als Fingerprint bezeichnet, da er eine nahezu eindeutige Kennzeichnung einer größeren Datenmenge darstellt, so wie ein Fingerabdruck einen Menschen nahezu eindeutig identifiziert.[3]

Die einzelnen Elemente in diese Speicherstruktur ermitteln ihren Index also weitestgehend selber. Der Index erstellt sich dann weiterhin aus der Abhängigkeit zur Kapazität des Sets. Wird die Kapazität vergrößert, so liegt theoretisch auch das Element an einer anderen Stelle. Des Weiteren muss das Element noch mit der Equals-Methode auf Eindeutigkeit geprüft werden. Der Vorteil dieser Speicherstruktur ist, dass ein Element auch wirklich nur ein mal vorkommt. Ebenso ist der Zugriff auf definierte Elemente sehr schnell, da nicht jedes Element geprüft werden muss.

Map

Bei der letzten Speicherstruktur handelt es sich um eine Map, oder Tabelle. Diese arbeitet im Grunde genommen genauso wie ein Set mit Schlüssel-Wert-Beziehung. Denn es wird zu jedem Schlüssel ein Wert abgelegt. Wobei ein Schlüssel in der Datensammlung immer eindeutig sein muss. Die einzelnen Schlüssel sind organisiert wie die Elemente in einem Set. Somit kann auch ein Zugriff sehr schnell erfolgen. Hauptsächlich wird diese Speicherstruktur als Cache genutzt. Um sich also Daten vor zuhalten und sehr schnell wieder auf diese zuzugreifen.

Fazit

Ich hoffe eine grobe Zusammenfassung über die Arbeitsweise sowie die Vor- und Nachteile einzelner Speicherstrukturen gegeben zu haben. Somit sollten Speicherstrukturen effizient genutzt werden können. Womit ich meine, dass nur die Vorteile genutzt werden sollten!

Links

  1. Collections Framework Overview
  2. Einfach verkettete Liste
  3. Hashfunktion – Wikipedia
Categories: Informatik Tags:

Valide Seite

27. März 2010 sep 4 Kommentare

Ich bin gerade mal dabei meine gesamte seite zu checken ob diese w3 konform ist. Und dabei habe ich am Anfang festgestellt, das dies nicht wirklich der Fall ist. :D Insgesamt bin ich eigentlich nur darauf gekommen, weil ich meine Seite für Suchmaschinen optimieren wollte und bin dabei einige viele Erkenntnisse zu gewinnen. Das Theme, welches ich verwende sollte XHTML 1.1 konform sein. War es aber nicht. Zum einen liegt dies an einigen Artikeln von mir. Wovon ich ja nun nicht allzu viele habe! ^^ Jedoch auch zum Teil an Wordpress. Bestes Beispiel ist das Einbinden von externen Links im Blogroll. So werden diese jeweils wie folgt dargestellt.

<a href="http://www.extern.net/" target="_blank">Extern.net</a>

Leider ist dies aber nicht konform. So zieht sich dies Beispielsweise durch ganz Wordpress durch, wenn man einen externen Link einrichtet, oder einen Link, welcher speziell geöffnet werden soll. Konform ist dies nicht mehr, da das target-Attribut in XHTML 1.1 abgeschafft wurde (in XHTML 1.0 Strict war dies wohl noch enthalten). Das hat folgenden Grund, wie ich hier[1] nachlesen konnte und den ich auch gut akzeptieren kann. HTML bzw XHTML ist eine Formatierungssprache und hat keinen Einfluss auf Layout (CSS) oder Ablauf (JavaScript). (X)HTML ist nur für die Struktur einer Seite zuständig. Denn Webcrawler interessieren sich nicht für Ablauf oder Layout. Genauso Browser wie Lynx oder Links oder ähnliche. Auch Handys haben damit vielleicht Probleme. Also wird das öffnen einer Seite dem JavaScript zugemutet. In dem Forenbeitrag[1] war dann auch vermerkt, wie dis von statten gehen soll.

<a href="http://www.extern.net/" onclick="window.open( 'http://www.extern.net/', '_blank' ); return false;">Extern.net</a>

Mit “window.open” also das neue Fenster in dem entsprechenden Ziel. Das “return false” ist dafür wichtig, wenn der Browser kein JS versteht. Dann wird direkt der hinterlegte Link angesprungen.

Eine weitere Quelle für Fehler lag ebenfalls bei dem a-Tag. Denn diese Tag kann man auch als Anker benutzen, um im Dokument irgendwo hin zuspringen. Normalerweise hatte ich das auch damals mit dem name-Attribut bezeichnet und dann ging das schon. Das fällt leider auch flach in XHTML 1.1. Der Beitrag[2] den ich dazu gefunden habe, war ein bisschen kürzer. Von nun an benutze ich dort nun auch das id-Attribut.

<a id="marke" href="http://www.extern.net/" target="_blank">Extern.net</a>
<a href="#marke">zur Marke springen</a>

Als nächstes bleibt noch das Einbinden von externen Flash-Inhalten. Dort bin ich über das w3 zu einer Lösung[3] des Problems gekommen. Das embed-Tag fällt vollständig weg und ich bleibe nur noch beim object- und param-Tag. Wie der nachher zum Schluss aussehen wird, werde ich dann nochmal zeigen. Denn ganz so wie ich ihn haben will, ist der Tag noch nicht.

Ein weiteres Problem war die Galerie-Funktion von Wordpress in den Artikeln. Denn die Hauseigene Galerie hat einen Style-Tag in die Seite eingebunden, was der Validator nicht ganz so fein fand. Nach längerem, erfolglosem Suchen in dem Code habe ich mich dann entschieden eine externe Galerie als Plugin einzubinden. Dafür habe ich mich für die nextGen-Galerie[4] entschieden. Diese gefällt mir eigentlich ganz gut und ich danke für den Tipp. Damit war dann auch das Problem mit dem ominösen Style-Tag beseitigt, welcher bei jeder Galerie in Worpress auftrat.

Zur Zeit sieht es einigermaßen valide auf meiner Seite aus. Wobei einigermaßen jedoch nur 14 von 22 Artikeln/Seiten meint. Ebenfalls ist mein Blogroll zwar noch angezeigt, aber erst einmal wird es wohl leer bleiben, bis ich dort etwas gefunden habe. Mal schauen, wie es denn noch weiter geht und wie lange ich noch brauche um meine Seite suchmaschinenfreundlich zu machen. Einen Link[5] möchte ich aber noch einmal genannt haben. Dort gibt es eine schöne Erklärung mit dem “www-ahnsinn” und was das mit Frundlichkeit zu tun hat. Danach fehlt mir nur noch eine schöne robots.txt und dann denke ich das alles in Butter ist! ;)

Links

  1. Validierung XHTML 1.1: target=”_blank”
  2. The a name-attribute and XHTML 1.1 Strict
  3. Flash Satay: Embedding Flash While Supporting Standards
  4. NextGEN Gallery
  5. wwwahnsinn
Categories: Informatik Tags: , ,

Dualboot mit Windows und Truecrypt-Verschlüsselung

24. Februar 2010 sep Keine Kommentare

Lange habe ich ja nicht mehr geschrieben. Aber nun melde ich mich doch mal wieder zurück, um zu beschreiben wie ich folgendes Problem gelöst habe.  Nach einiger Zeit habe ich mir doch mal überlegt wieder einmal Windows 7 zu installieren. Ausschlaggebend dafür war mein Vater gewesen, hmm und ich… Da ich Windows eigentlich parallel ab und an mal nutze, brauchte ich einen Dualboot. Partitioniert war meine Festplatte schon. Also Windows DVD rein und einfach mal los installiert. Da meine Linux Platte ja schon mittels LUKS verschlüsselt ist, wollte ich nun auch meine Windows-Systempartition verschlüsseln. Also habe ich mir Truecrypt[1] installiert und dann dort angefangen meine Festplatte zu verschlüsseln. Dies geht dann wie folgt.

Truecrypt

Schritt für Schritt Anleitung, um die Systemplatte von Windows zu verschlüsseln.

23 Fotos

 

Wenn man dieser Galerie folgt, dann sollte es eigentlich kein Problem sein, die Systempartition zu verschlüsseln. Das ist auch nicht unbedingt eine unlösbare Aufgabe und es gibt relativ viele Anleitungen dazu. Nun wird es ein bisschen spannender. Denn wir brauchen nun noch eine Linux-Live-CD. Diese legen wir in das DVD-Laufwerk und booten neu. Selbstverständlich von der DVD/CD. Hat dieser nun durch gebootet und ist bereit, sichern wir uns den Bootsektor der Festplatte. Denn in diesem ist zur Zeit der Bootsektor von Trucrypt enthalten, welchen wir noch brauchen. Normalerweise ist der Bootsektor genau 512 Byte groß. Wie das nun mit neueren WD oder Samsung-Platten ist, weiß ich nicht. Denn diese haben die Sektorgröße auf 4kB gesetzt[2].Vorher mounten wir jedoch unser Boot-Laufwerk und lesen dann den Bootsektor der Festplatte aus.

mount /dev/sda2 /mnt/boot
dd if=/dev/sda ibs=512 of=/mnt/boot/windows_truecrypt.mbr count=1

Danach müssen wir dann noch den Eintrag in der grub.conf einfügen. Diese sieht bei mir folgendermaßen aus.

title Windows 7 Professional
rootnoverify (hd0,0)
makeactive
chainloader (hd0,1)/windows_truecrypt.mbr

Mit dem Chainloader[3] sagen wir ihm, dass dies direkt ausgeführt werden soll. Da sich in der mbr-Datei unser alter Truecrypt-MBR befindet, wird dieser halt ausgeführt. Danach wird der Windows Bootloader ausgeführt und Windows startet “ganz” normal. Also mit Passworteingabe. Nun müssen wir nur noch den alten Grub-Bootloader in den MBR schreiben und dann sollten wir auch schon fertig sein.

mount /dev/sda3 /mnt/gentoo
mount -t proc none /mnt/gentoo/proc
mount -o bind /dev /mnt/gentoo/dev
chroot /mnt/gentoo /bin/bash

grub

root (hd0,1)
Filesystem type is ext2fs, partition type 0×83

setup (hd0)
Checking if “/boot/grub/stage1″ exists… yes
Checking if “/boot/grub/stage2″ exists… yes
Checking if “/boot/grub/e2fs_stage1_5″ exists… yes
Running “embed /boot/grub/e2fs_stage1_5 (hd0)”… 17 sectors are embedded.
succeeded
Running “install /boot/grub/stage1 (hd0) (hd0)1+17 p (hd0,1)/boot/grub/stage2 /boot/grub/menu.lst”… succeeded
Done.

quit

exit

umount /mnt/gentoo/dev
umount /mnt/gentoo/proc
umount /mnt/gentoo
umount /mnt/boot

Wenn es dort keine Fehler gab, dann sollte alles funktionieren. Nach einem Neustart sollte Grub wieder der Bootloader sein. Wenn man nun sein Linux auswählt, startet der wie gewohnt. Bei Windows sollte danach der Bootloader von Truecrypt kommen. Dort dann das Passwort eingeben und Windows sollte dann auch wieder starten.

Links

  1. TrueCrypt – Free Open-Source On-The-Fly Disk Encryption Software
  2. heise – Festplatten mit 4 KByte Sektorgröße
  3. GNU GRUB Manual 0.97 – chainloader
GNU GRUB Manual 0.97

Java und Call-By-Reference

23. November 2009 sep 1 Kommentar

Hey, ich arbeite ja mal wieder an einem Projekt, und bin dort ein mal auf ein kleines Problem gestoßen. Nämlich einen nativen Typen in einer Funktion zu bearbeiten. Eigentlich kein Problem. Zumindest kann man diesen ja zurück geben, per return. Jedoch hatte ich dort schon einen anderen Rückgabewert.  Also, kann man sich nun noch eine neue Klasse schaffen, um dort mehrere Sachen zurück zu geben. Jedoch war mir das nicht elegant genug.

Dann kam ich auf eine Idee, welche ich aus C, C++ und C# kenne. Nämlich das Call-By-Reference[1]. Unter C# ist es wie folgt möglich.

TryParse( String str, ref int value );

Doch unter Java ist das nicht so einfach. Denn folgendes ist dort der Fall. Da sehr viele Programmierfehler auf Zeiger zurück zu führen sind, hatte man die Zeiger in der Sprache sozusagen abgeschafft. Sie sind für uns also nicht mehr sichtbar. Nun ist die objektorientierte Programmierung ohne Referenzen aber nicht möglich. Denn auf jedes Objekt, welches instantiiert wird, gibt es eine Referenz. Diese Referenz wird als Kopie an eine Funktion übergeben. Und die Funktion arbeitet dann damit. So ist es möglich, dass Eigenschaften in einem Objekt geändert werden könne und außerhalb der Funktion diese Änderungen auch noch “aktiv” sind. Sie wurden also nicht zurück geändert. Jedoch kann man das Objekt an sich nicht verändern. Also neu instantiieren und dies dann über die Parameter zurück geben. Native Datentypen werden alle als Kopie übergeben. So fällt der Aspekt des Änderns weg. Also dachte ich mir, es gibt ja Wrapper-Klassen und so wollte ich eine nutzen. Denn dort werden wieder die Referenzen weiter gegeben und ich könnte die Eigenschaften ändern. Aber mir ist dann aufgefallen, dass ich die Eigenschaften in der Wrapper-Klasse nicht bearbeiten kann, da mir die Zugriffskontrolle dies verbietet. Blöd! Also wollte ich mir selber eine Wrapper-Klasse schaffen. Jedoch kann es ja sein, dass Java so was bietet. Also machte ich mich auf die Suche und hab nichts gefunden. (Wenn es so was gibt dann sagt mir Bescheid! :D ) Naja. Wie auch immer. Im Java-Forum[2] wird davon gesprochen einfach ein Array-Objekt zu übergeben. In einem Array sind die Werte gespeichert. Von dem Array wird dann eine Kopie der Referenz übergeben und ich könnte meine Werte bearbeiten. Funktioniert zwar, war mir aber nicht schön genug.

Nach einiger erfolgloser Suche habe ich mir dann eine eigene Wrapper-Klasse geschrieben.

package org.seplog.javrsimulator.util;

/**
 * Diese Klasse ist eine Wrapper Klasse. Hierdurch können alle möglichen
 * Typen, Klassen und Objekte einer Funktion als Referenz übergeben
 * werden.
 *
 * @author Sebastian Koschmieder
 * @date 17.11.2009
 * @mail sep@seplog.org
 * @param < T >
 *            Ist der Typ der Klasse, welche übergeben wird.
 */
public final class ByReference< T > {

    /******* Member ****************************/

    /**
     * Dies ist der Wert, welcher als "Referenz" übergeben wird.
     * Da mit diesem Wert durch beide Bearbeiter gleichermaßen
     * bearbeitet werden können muss, findet keine
     * Zugriffskontrolle statt.
     */
    public T value;

    /******* Konstruktoren *********************/

    /**
     * In dem Konstruktor wird nur die Variable übergeben.
     *
     * @param value
     *            Dies Variable wird als Referenz behandelt.
     */
    public ByReference( T value ) {
        this.value = value;
    }

}

Die Verwendung dieser Klasse ist ganz einfach. Ich instantiiere mir ein ByReference-Objekt, welchem ich im Konstruktor mein Objekt gebe. Danach übergebe ich die ByReference-Klasse an die Funktion. Beide, also Aufrufer und die aufgerufene Methode können nun das Objekt gleichermaßen bearbeiten.

package org.seplog.javrsimulator.util;

public class Program {

    public static void main( String[] args ) {

        ByReference< Integer > reference = new ByReference< Integer >( 42 );
        System.out.printf( "Wert: %d\n", reference.value );
        changeRef( reference );
        System.out.printf( "Wert: %d\n", reference.value );

    }

    public static void changeRef( ByReference< Integer > reference ) {
        reference.value = 1337;
    }
}

Links

  1. Referenzparameter – Wikipedia
  2. Lösung Java-Forum
Categories: Informatik Tags: , ,

Rette deine Freiheit

10. Oktober 2009 sep Keine Kommentare

Habe was gefunden, was sich sehr anzuschauen lohnt[1]. Mehr dazu nicht, außer ein kleines Zitat.

Wenn wir Angst haben, raschelt es überall.

Von Sophokles.

Zur Anzeige des Videos benötigen Sie den Adobe Flash Player,
welchen Sie hier herunterladen können.

Links

  1. Rette deine Freiheit