Dienstag, November 22, 2016

Kein Spass mit tar

Da versuche ich also, eine virtuelle Maschine aus Dateien in einem Verzeichnis auf einer anderen Maschine wiederherzustellen. Ich habe eine Live-CD in meiner neuen Maschine, partitioniere und formatiere die Platte, mounte sie, und ... ja, jetzt gehts los...

Auf der sendenden Seite mache ich ein tar cvz . | netcat 1.2.3.4 12345, auf der empfangenden Seite mache ich ein netctat -l -p 12345 | tar xz und kopiere so alle Dateien auf die neue Maschine rüber. Leider beendet sich der Stream nicht richtig, und nachdem alle Dateien kopiert wurden, muss ich noch mit Ctrl-C das netcat abbrechen.
Jetzt noch schnell den Bootloader einrichten, und ich bin fertig! Dazu kann ich ja einfach in einem root-Jail update-grub und install-grub verwenden!

chroot /mnt /bin/bash 
permission denied

Das kann ja wohl nicht wahr sein!

Stellt sich raus, dass zB /bin/systemd eine leere Datei ist auf meinem neuen System. Auf meinem alten ist es ein Symlink nach /lib/systemd/systemd. Wieso ist es eine leere Datei? Da sind noch mehr leere Dateien... Vielleicht auch Libraries? Ich suche nicht alles ab. Nach viel googlen finde ich raus, es ist wie folgt...:

tar entpackt Symlinks aus einem merkwürdigen Sicherheitsgrund nicht direkt, sondern erstellt Platzhalterdateien, die in einem zweiten Lauf erst (wenn sich die Platzhalterdateien nicht verändert haben) durch Symlinks ersetzt werden. Da der mein Netzwerkstream sich nicht richtig beendete, musste ich tar und netcat ja mit Ctrl-C abbrechen, und da ich mir keine Gedanken darüber machte, machte ich das auf der empfangenden Seite. Damit habe ich aber verhindert, dass dieser zweite Lauf durchlaufen konnte, und behielt leere Dateien. Meine Kopie war nicht in Ordnung, chroot funktionierte nicht.
Als ich aber auf der sendenden Seite mit Ctrl-C abbrach, konnte sich tar auf der empfangenden Seite korrekt beenden, seinen zweiten Lauf machen (den man nicht mitbekommt. Es beendet sich einfach), und zack! meine Kopie ist in Ordnung!

Danach funktionierte alles. Mal wieder zwei Stunden im weg mit unvorhersehbarem!

Mittwoch, November 16, 2016

Firefox fix machen

Ich habe endlich eine Möglichkeit gefunden, meinen Firefox zu beschleunigen. Die Lösung ist es, die ganzen Optimierungen abzuschalten.

javascript.options.asmjs = false
javascript.options.baselinejit = false
javascript.options.ion = false
javascript.options.compact_on_user_inactive_delay = 15000

Die JIT-Compilate brauchen entweder viel Speicher oder sind nicht gut mit der Garbage-Collection kompatibel, ich weiss es nicht. Mit diesen Einstellungen fahre ich meinen Firefox von manchmal bis zu 2,5GB, wo die GC ständig zuschlägt aber nix wegräumt auf eher 1,2GB runter, und die GC funktioniert.

ion, baselinejit und asmjs sind dazu da, Javascript schneller auszuführen. Meine Maschine ist mittlerweile eigentlich schnell genug, das auch ohne diese Optimierungen zu schaffen, und diese Optimierungen zerstören offenbar die Speicherverwaltung.

(Bezüglich Firefox 49.0.2)

Donnerstag, Juli 21, 2016

Spass mit tun/tap unter Linux

Heute hab ich ein bisschen Spass mit dem tun/tap-Treiber von Linux gehabt. 

Hier die einfache tun_alloc() abgeschrieben. Mein Code liest nun endlos (die meisten Beispiele benutzen select(), aber ich blockiere einfach) Pakete, vertauscht Source- und Destination-Address, und schreibt es wieder zurück auf das Interface. Das ist insgesamt nicht besonders sinnvoll, 
... aber ...
obwohl es eine Checksumme (crc32) gibt, die den Header sichern soll, kann man trotzdem, ohne die neu zu berechnen, einfach Source- und Dest-Adresse tauschen, weil die crc32 trotzdem korrekt bleibt. Eine merkwürdige Eigenheit dieses Checksummenalgorithmus.

Trotzdem nicht besonders sinnvoll, aber es gibt ein Protokoll, das genauso funktioniert: Ping! Und siehe da, ping geht auch.

Wichtig, was mir etwas Kopfzerbrechen gemacht hat: Das tuntap-Interface liefert einem einen File-Deskriptor, dem man mit read() und write() bearbeiten kann. Allerdings liefert read() immer ein Paket von Anfang an. Man kann nicht "testweise" in ein Paket reinlesen und dann im Header nachschauen, wie lang das Paket noch ist, und dann ein passendes zweites read() aufrufen, wie man das vielleicht bei einem tcp-Stream tun würde oder bei einer Datei.

So, jetzt mal Butter bei die Fische:

Mein Code:
tuntaptest.c
--------------------

// Tun/Tap Test

#include <sys/socket.h>    //Mo: or else doesn't compile. (errors in if.h)
#include <linux/if.h>
#include <linux/if_tun.h>

#include <sys/select.h>

#include <netinet/ip.h>
#include <unistd.h>

#include <stdio.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdlib.h>

#include <arpa/inet.h>

/////////////////////////////////////////////////////////
// copied from https://www.kernel.org/doc/Documentation/networking/tuntap.txt

int tun_alloc(char *dev)
{
  struct ifreq ifr;
  int fd, err;
  
  if( (fd = open("/dev/net/tun", O_RDWR)) < 0 )
    perror("open(/dev/net/tun) < 0");
  
  memset(&ifr, 0, sizeof(ifr));
  
  /* Flags: IFF_TUN   - TUN device (no Ethernet headers) 
   *        IFF_TAP   - TAP device  
   *
   *        IFF_NO_PI - Do not provide packet information  
   */ 
  ifr.ifr_flags = IFF_TUN | IFF_NO_PI;   //Mo: ohne IFF_NO_PI hatte ich ein padding-Problem.
  //ifr.ifr_mtu   = 1500;      // Mo: Hinzugefuegt.
  
  if( *dev )
    strncpy(ifr.ifr_name, dev, IFNAMSIZ);
  
  if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
    close(fd);
    return err;
  }
  strcpy(dev, ifr.ifr_name);
  return fd;
}

//////////////////////////////////////////////////////////////////////

void printip(u_int32_t addr)
{
  printf("%i.%i.%i.%i", addr&0xff, (addr>>8)&0xff, (addr>>16)&0xff, (addr>>24)&0xff);
}

union {
  unsigned char ip_packet[65536];
  struct iphdr iphdr;
} packet;

int main(int argc, char **argv)
{
  char devname[IFNAMSIZ] = "mirror%d";
  int fd, n;
  u_int32_t swaptmp;

  fd = tun_alloc(devname);
  printf("devname: %s\nfd: %i\n", devname, fd);
  printf("sizeof iphdr = %lu\n", sizeof packet.iphdr);
  fflush(stdout);

  while (1) {
    // Genau ein read() pro Paket.
    // Wenn man nicht das ganze liest (bspw. erstmal nur den Header)
    // bekommt man den Rest nicht mehr.
    n = read(fd, &packet, sizeof packet);

    printf("Source IP: ");
    printip(packet.iphdr.saddr);
    printf(" Dest IP: ");
    printip(packet.iphdr.daddr);
    printf(" headerlength=%i", packet.iphdr.ihl);
    printf(" length: %i\n\n", n);
    
    ///// Wir swappen nun daddr und saddr und
    // schreiben das paket zurueck auf die
    // leitung.
    // WENN das ein ping war, muesste es korrekt
    // beantwortet sein. Wenn nicht, passieren halt
    // komische dinge, aber wen interessierts. ;)

    swaptmp = packet.iphdr.saddr;
    packet.iphdr.saddr = packet.iphdr.daddr;
    packet.iphdr.daddr = swaptmp;

    write(fd, &packet, sizeof packet);
  }
}





Dazu gibt es dann ein kleines Configscript:

configtun.sh
------------
#!/bin/bash

ip addr add 192.168.123.1/24 dev mirror0
ip link set up mirror0


Und nun führen wir das ganze aus:

$ gcc tuntaptest.c -o tuntaptest
$ sudo su # ich bin grad auf einem ubuntu...
$ modprobe tun
$ ./tuntaptest

# ... neue shell ...
$ sudo su
$ bash configtun.sh
$ ip addr
...
mirror0   Link encap:UNSPEC  Hardware Adresse 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 
          inet Adresse:192.168.123.1  P-z-P:192.168.123.1  Maske:255.255.255.0
          UP PUNKTZUPUNKT RUNNING NOARP MULTICAST  MTU:1500  Metrik:1
          RX-Pakete:6 Fehler:0 Verloren:0 Überläufe:0 Fenster:0
          TX-Pakete:6 Fehler:0 Verloren:0 Überläufe:0 Träger:0
          Kollisionen:0 Sendewarteschlangenlänge:500
          RX-Bytes:393216 (393.2 KB)  TX-Bytes:264 (264.0 B)


schonmal ganz cool...

und nun ...
# ping 192.168.123.42
PING 192.168.123.42 (192.168.123.42) 56(84) bytes of data.
64 bytes from 192.168.123.42: icmp_seq=1 ttl=64 time=1.08 ms
64 bytes from 192.168.123.42: icmp_seq=2 ttl=64 time=0.668 ms
64 bytes from 192.168.123.42: icmp_seq=3 ttl=64 time=0.335 ms
^C
--- 192.168.123.42 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 0.335/0.696/1.085/0.306 ms


# ping 192.168.123.23
PING 192.168.123.23 (192.168.123.23) 56(84) bytes of data.
64 bytes from 192.168.123.23: icmp_seq=1 ttl=64 time=0.340 ms
64 bytes from 192.168.123.23: icmp_seq=2 ttl=64 time=0.433 ms
64 bytes from 192.168.123.23: icmp_seq=3 ttl=64 time=0.575 ms
^C
--- 192.168.123.23 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
rtt min/avg/max/mdev = 0.340/0.449/0.575/0.098 ms


antwortet einfach jede Adresse in dem Subnetz :)

Mittwoch, Mai 04, 2016

Using a remote pulseaudio to mitigate Virtualbox soundproblems

Applicability

I had this problem with audio in my Virtualbox guest, Xubuntu, on my Mac OS X host.
But this should be applicable -- in part or in whole -- to any host which is able to run pulseaudio and ssh and any unix guest which uses pulseaudio as defaultsoundsystem.


What did go wrong?

So i have this Mac from work, but I like working under Linux, xfce, sometimes I install debian, sometimes Xubuntu. This I did in a Xubuntu guest in Virtualbox on a Mac OS X host.
So I like using my Xubuntu, and I use it for most things that work: Watching movies, listening to music, working, everything. So I like the audio to work.

It does mostly work, but not perfect. Sometimes I connect the Macbook to a bluetooth audio receiver or plug in the hdmi to watch something on my tv screen. Sometimes I plug in headphones. All of these are visible in the audio menu up top, which shows a list of all this devices when I alt-click it. I can choose an audio output device from this list and the Mac promptly plays over that device. 
But not the Virtualbox. The Virtualbox just stays on the device it was playing audio over when it got startet. It doesn't switch to what I choose. (Sometimes it did, but not always, and that got very annoying)


The Solution

This one is kind of complicated.

the host

First, you have to install pulseaudio on your host machine, I did this with brew install pulseaudio, using homebrew.

Now, you have to configure your pulseaudio so you can use it over the net:
pulseaudio --dump-conf dumps you the pulseaudio config which includes the path of the default.pa file which we have to edit. On my machine it lies under
/usr/local/Cellar/pulseaudio/8.0/etc/pulse/default.pa
In this file, there is a commented out line which loads the module
module-native-protocol-tcp
I commented that line in and added some parameters:

load-module module-native-protocol-tcp  auth-ip-acl=127.0.0.1;192.168.0.0/24;10.0.2.15 auth-anonymous=1
(yeah, I googled that, don't really know, what that's doing, although I have an idea, of course. You can adjustt the IP ranges of course, in this example, we will only use the 10.0.2.15)

In the same directory as the default.pa there is another config file named daemon.conf. In this file you set allow-exit=no and comment out the exit-idle-time so pulseaudio doesn't exit if it's idle.

the guest

On the guest, you only have to run pax11publish -e -S 10.0.2.2 where 10.0.2.2 is the IP of the host, and you should be able to use the host's pulseaudio to play sound. done.

Automating it

Make sure you have an ssh-server on the host. Have an ssh-client on the guest. Create a keypair on the guest with ssh-keygen and configure everything so that you can connect from the guest to the host without a password.

Install screen on the host using brew install screen screen. Also, create a script:
cat > startpulseaudio.sh << EOF
#!/bin/bash
exec > ~/.pulselog 2>&1
echo starting pulse
pulseaudio
echo pulse aborted

EOF

On the guest, you create a script:
cat > starthostaudio.sh << EOF
#!/bin/bash

ssh -vT 10.0.2.2 "bash -l -c 'screen -S hostaudiopulse -d -m bash ~/startpulseaudio.sh'"
pax11publish -e -S 10.0.2.2
EOF


where -- as before -- 10.0.2.2 stands for the host IP.

Add starthostaudio.sh to your autostart on the guest, and you should be all set.

Well d'uh!


Dienstag, Februar 02, 2016

ZMODEM lebt!

Ja, ist super, um Dateien irgendwie durch ssh-Tunnel zu kopieren!
Auf beiden Endpunkten "lrzsz" (Das sind die Kommandos "sz" und "rz") installieren.
Auf dem Endgrät benötigt man "screen", denn Terminals, die selbst noch ZMODEM beherrschen gibt es quasi nicht mehr.

Screen kann man dazu animieren, ZMODEM Kontrollcodes zu erkennen und darauf zu reagieren. Allerdings braucht auch Screen dazu dann sz oder rz.
Diese Funktion muss auch noch aktiviert werden.
Entweder im laufenden Screen "C-a : zmodem catch", bzw "C-a : zmodem auto" (letzteres sollte auch richtig funktionieren).
Stattdessen kann man auch in die ~/.screenrc "zmodem auto" schreiben.

Auf dem Zielgerät müssen auch sz und rz installiert sein. Will man nun eine Datei senden, so gibt man auf dem Zielgerät "rz" ein (Das heisst "Receive ZMODEM"), Screen erkennt den darauf folgenden Kontrollstring und läd dazu ein, lokal das entsprechende sz-Kommando auszuführen, die Switches sind vorausgefüllt, und man muss nur noch den Dateinamen angeben.

Will man vom Zielgerät eine Datei empfangen, so benutzt man stattdessen "sz" (Dann sendet das Zielgerät, deshalb gibt man dort sz = "Send ZMODEM" ein).

scp ist wohl üblicherweise einfacher, ausser, man möchte mehrere Hops überbrücken.

Ausserdem: ZMODEM war früher gut!