Thursday, March 31, 2011

Setup your own DLNA server

DLNA is a standards-based technology whose main goal is to ease the sharing of multimedia contents. DLNA is an open protocol based on UPnP.

This article describes how to install and configure a DLNA server. This software is going to be installed on a home server. Just as a comment, this home server is a very low power consumption machine (Atom N550 board) running a very powerful OS: 64 bit CentOS 5.5.

We started with a brief comparison and testing of some of the most popular DLNA servers for Linux uShare, MediaTomb and MiniDLNA). That was not an exhaustive comparison, but just a few quick tests. After that quick preview, we finally decided to use MiniDLNA.

The authors of the MiniDLNA project offer a statically compiled version, which makes very easy to install the software. Download it, and optionally, you can make some changes to file permissions in order to keep them consistent with the rest of your system.

Let's assume that you downloaded the installation package on /tmp

Previously to the installation, we set root as the owner of the files (optional) just to avoid having an unreferenced owner, then, we unpack the software.


# mkdir /tmp/mini
# tar -xzf /tmp/minidlna_1.0.19_static.tar.gz -C /tmp/mini
# chown -R root:root /tmp/mini
# cp -r /tmp/mini/* /


The configuration is really simple. You have a self-explaining configuration file (/etc/minidlna.conf) with a few options. Just indicate which interface are you running the service on, and the directory containing the media to share. In my case, these were the only changes I made, keeping the rest of the options with the default values.


network_interface=eth0
media_dir=/usr/local/media/
friendly_name=Multimedia


The most difficult task is to configure the firewall (iptables, since it is a CentOS based server) properly. This home server offers public services to the outside. External services are separated from internal ones, being offered through a different interface. Even so, disabling the firewall is not an option.

First of all, we launch the service just to examine the ports that must be kept open:


# /usr/sbin/minidlna
# lsof -i4 -n | grep minidlna
minidlna 12964 root 8u IPv4 1155301 UDP *:ssdp
minidlna 12964 root 9u IPv4 1155302 TCP *:trivnet1 (LISTEN)
minidlna 12964 root 10u IPv4 1155303 UDP 192.168.1.8:37167
minidlna 12965 root 8u IPv4 1155301 UDP *:ssdp
minidlna 12965 root 9u IPv4 1155302 TCP *:trivnet1 (LISTEN)
minidlna 12965 root 10u IPv4 1155303 UDP 192.168.1.8:37167
minidlna 12968 root 8u IPv4 1155301 UDP *:ssdp
minidlna 12968 root 9u IPv4 1155302 TCP *:trivnet1 (LISTEN)
minidlna 12968 root 10u IPv4 1155303 UDP 192.168.1.8:37167


Ports ssdp (1900/udp) and trivnet1 (8200/tcp) are proper of this service. The other port (37167/udp) varies in every execution.

I recognize not being an expert setting firewall rules, but firewall configuration in CentOS in this case resulted to be a very frustrating task.

After almost two whole days spent reading threads, tutorials and comments about UPnP, SSDP, DLNA, multicast, routing and filtering, I finally obtained a firewall configuration that, so far, seems to work properly. Neither more permissive than necessary nor too much complicated.

Maybe due to my limited knowledge about iptables, I was not able to introduce these rules from the command line to behave as I expected, so, I had to edit, finally, the /etc/sysconfig/iptables file in order to introduce these rules. I added two rules in the RH-Firewall-1-INPUT section, just before the REJECT rule.


...
-A RH-Firewall-1-INPUT -s 192.168.1.0/24 -d 192.168.1.8 -p tcp -m tcp --dport 8200 -j ACCEPT
-A RH-Firewall-1-INPUT -s 192.168.1.0/24 -d 239.255.255.250 -p udp -m udp --dport 1900 -j ACCEPT
-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited
COMMIT


The IP 192.168.1.8 is where the machine offers services to other devices in the LAN (192.168.1.0/24)

First rule allow computers on the LAN to access the server on the port 8200/tcp
Second rule allow computers on the LAN (including the same server) to access the SSDP service (1900/udp) on a fixed multicast address (239.255.255.250)

Restart iptables after these changes, and you will have a working DLNA server without compromising the security of your server.

Saturday, March 26, 2011

Download Flash videos

Today there is a lot of websites with video contents. Most of them use flash as the platform to deliver the video contents to web browsers.

There can be many reasons to prefer to download the contents instead on watching them online, but unfortunately, many sites do only allow to watch the video contents while the user is connected to the corresponding website.

Older versions of flash player (previous to fall of 2010), just created a temporal file containing a cached copy of the video content. This way, getting a copy was an easy task: The user had just to locate the file containing the cached video to make a copy of such a file.

Current versions does not seem to create anywhere such a copy of the video.

In recent versions, such a file has been hidden trying to difficult to get a copy of the contents shown in the player. The trick is to use a deleted file as video cache. This way, the user is unable to find this file, at least in the usual way.

Here, we present a simple script whose goal is to get a copy of the deleted cache video file used by the flash player:


#! /bin/bash

RECPATH=/tmp
PIDS=`ps aux | grep libflashplayer | grep -v npwrapper | grep -v grep | awk '{print $2}'`
for PID in $PIDS
do
FFILES=`ls -la /proc/$PID/fd/* | grep Flash | awk '{print $8}'`
for FFILE in $FFILES
do
FNAME=`tempfile -d $RECPATH -p vid_ -s .flv`
cp -f $FFILE $FNAME
echo "Recovered file: "$FNAME
done
done


Usage:

Using your favourite editor, create a script with the above commands.
Place it on any convenient location (for all users, like /usr/sbin, or just for your own ~/scripts ), and do not forget to give it execution permissions, i.e:


$ sudo vi /usr/sbin/capture_flash


Copy the above lines to this file. You can change the destination folder location (/tmp in the sample script) or modify the script to receive the destination as a parameter.


$ sudo chmod +x /usr/sbin/capture_flash


Open your browser, point to a site containing a flash player. Let the player buffer the full video contents and then execute the script.


$ capture_flash


Now you will have a copy of the video being played in the embedded viewer. You can rename it, and eventually move it to a more convenient location.


Explanation:

First of all, the script obtains the PID of all running instances of flash player. The npwrapper is excluded, considering that you can be running the 32 bit version on a 64 bit system


PIDS=`ps aux | grep libflashplayer | grep -v npwrapper | grep -v grep | awk '{print $2}'`


The script iterates through the identified PIDs examining the file descriptors associated with every process. Flash cache files can be identifies easily since they are the only ones containing the pattern 'Flash' on their names. Here we obtain references to the deleted cache files (unreachable and invisible otherwise).


FFILES=`ls -la /proc/$PID/fd/* | grep Flash | awk '{print $8}'`


For every flash file identified, the script generates a unique name on the destination directory, and finally copies the file descriptor of the deleted cache file to an ordinary file.


FNAME=`tempfile -d $RECPATH -p vid_ -s .flv`
cp -f $FFILE $FNAME


You got it!

Note: The script has been successfully tested on Firefox 3.6.x and Chromium-browser 10.0.x with flash 10.2.x running on Ubuntu 10.04 x86_64. Comments and improvements are welcome.