Suspend and continue processes (ctrl+z) in a shell script

13 January 2014

If you have spend some time in a command line environment you have probably run into the problem of wanting to run multiple programs at once. In a unix-like shell you can do this in many different ways. You could open up a second TTY (ctrl+alt+f2), use a terminal multiplexer like screen or tmux, or you can launch the process in the background from the beginning by appending an ampersand (command &). Often it is after you have already launched the program that you realize you need to run another command from the same terminal. To do this, you can first suspend it with the key combination (ctrl+z) and then push it to the background with bg or disown it with the disown command if your shell supports that.

Control-z is very interesting because it suspends the process you are running, effectively pausing it. It works by sending the TSTP signal to the process. This can be very convenient if you just need to clear up some processing power or have another reason to give your process a break before continuing (like for example pausing tar if your volume is about to have no space left). The Control-z functionality can be simulated by running kill -TSTP $PID with $PID as the process ID of your process. Just like you might resume the process with fg in the command line, you can run kill -CONT $PID to un-pause the process. So if you were to implement this in a shell script, you could do something like

$ command & COMMANDPID=$!

and then do

$ kill -TSTP $COMMANDPID

to pause your process after initial execution ($! catches the PID of the last launched process in the shell, if you get "-bash: !: event not found" add a whitespace after the !). The problem with this approach is that this functionality is mostly useful when you are running parts of your script parallel and already in the background or in subshells, and if that is the case then doing kill -TSTP might not be good enough.

You can run a script or program with lots of subprocesses or subshells and neatly pause it with Control-z. If you'd try the same thing with the kill -TSTP command in a complex shell script you might run into some difficulties. The difference here is that kill -TSTP only sends the signal to the highest PID in the hierarchy and the signal won't reach all the levels. This is often not a problem because most scripts don't go that deep, if you want that level of abstraction for system stuff you are probably better of with some scripting language like python or perl. But hey, in the spirit of why not: to make sure you are actually suspending the entire process chain you can do something like this.

$ for childprocess in $(ps -o pid --ppid $PID | tail -n +2); 
    do kill -TSTP $childprocess; 
  done;

replace TSTP with CONT to continue the chain. Watch out though, the --ppid flag (select by parent process ID) is not supported on FreeBSD so if that's your platform you might have to figure out something else.

Permalink


Not authorized to use this service in DS Audio and Video

21 September 2013

Since I updated my phone to iOS7 I've been encountering the following error when attempting to log in using the DS Audio and Video apps.

"you are not authorized to use this service"


Reinstalling the apps didn't solve the issue for me and the error seemed exclusive to my phone as logging in still worked flawlessly on other devices running the same version of the OS.

Since I didn't want to resort to resetting my phone, I did some more troubleshooting and these are the solutions (and possible problems causing the error) I came across, so if you are experiencing the same error, trying these things might save you a headache.


Checking the automatic block-list

To check if this problem is causing your error, change the ip address of your iOS device and attempt to log in. If the error no longer occurs, there is a good chance that the Synology NAS has blocked your ip address.

To make sure this was the cause of the problem, and to possibly prevent future similar things from happening do the following:

In the DSM control panel, click on the icon of Auto Block and see if you have this option enabled. Also check the Block List tab to see if some (or any) of the ips listed there are those of your devices.

If you have shell access to the NAS you can also look in the files /etc/host.deny and /etc/hosts.allow to see if there is anything interesting there that might prevent you from logging in.

Updating the DSM time settings

If the previous bullet point didn't solve your problem, you might try updating the time settings of your DSM. Do this in Control Panel -> Regional Options -> Time. Try changing the Time Setting from 'Manually' to 'Synchronize with a NTP server' and press the 'Update Now' button. An offset of a couple of minutes could be enough to cause the 'you are not authorized to use this service' error. To achieve the same effect from the commandline, you could also run the following command:

# ntpd -q


Changing the iOS time setting from '24-Hour Time' to '12-Hour Time'

This step is what I think finally solved the problem for me. For some reason the combination of turning off 24 Hour time (and restarting the phone) was what enabled me to log into the Audio Station using the DS Audio app once again. I have no idea if this was what actually caused the problem, and I couldn't reproduce the problem afterwards either, but if the previous approaches were of no help, you could give it a shot.

If these three things didn't solve the problem for you, you could try to enable logging in the Audio Station -> Settings -> Options menu to take a look under the hood, and maybe this log in combination with the /var/log/synolog file will give you some insights on what might be the cause of your problem.

Permalink


Sending data over Wi-Fi without associations

01 August 2012

Sending data over Wi-Fi without associations

For the past couple of months I’ve been on and off working on a project I call sailingstone, although that particular project probably won’t see the light of day for a long time (if ever) it did point me in a direction that I found remarkably interesting. I needed to find a way to transmit data from one wireless card to another, without a router in between. There already exist various ad-hoc methods to achieve this, however most of them focus on a sole connection between two devices. For purposes such as mesh-networking it would be nice to be able to change connections swiftly or even broadcast to multiple nodes.

My first instinct was to just hurl packets into the air and have other nodes catch them. Imagine one laptop sending some bytes into the air containing a message, and another one grabbing those bytes. Unfortunately, that is not how things work. Wireless networking works by packing data into things called frames. This way a computer can very quickly decide if it has a use for an incoming packet by looking at the header. If that header does not meet the criteria of what your wireless card is configured for, it just ignores the packet and goes on to the next one.

You could modify how your wireless card acts by patching your drivers, but that wouldn’t be very practical due to incompatibility with other devices. Instead of doing that, we will utilize the existing infrastructure and add our data to a recognized frame. Using a tool called mdk3 I generated a fake beacon frame for an encrypted access point with the SSID ‘stone’. This is where it gets a bit technical.

Let’s create two programs, the first one being a transmitter and the second one being a receiver:

transmitter.c receiver.c

To compile these programs use the -lpcap flag:

$ gcc transmitter.c -o transmitter -lpcap
$ gcc receiver.c -o receiver -lpcap

In transmitter.c you can see how memcpy is used to first copy the frame header into the variable buf. This is interesting because you could use this method to capture any beacon frame, grab the header, and re-broadcast it with your added data. The crafted packet gets broadcast using the pcap_sendpacket function.

u_char buf[1024];
char message[850], messagelen[6];
char size[] = "size", end[] = "end";
char type[] =  "\x0\x0\xd\x0\x4\x80\x2\x0\x2\x0\x0"
        "\x0\x0\x80\x0\x0\x0\xff\xff\xff\xff"
        "\xff\xff\xf8\xb7\x6f\x7b\xc2\x59\xf8"
        "\xb7\x6f\x7b\xc2\x59\x0\x0\x0\x0\x0"
        "\x0\x0\x0\x0\x0\x64\x0\x11\x0\x0\x5"
        "\x73\x74\x6f\x6e\x65\x1\x4\x82\x84"
        "\x8b\x96\x3\x1\xc\x4\x6\x1\x2\x0\x0"
        "\x0\x0\x5\x4\x0\x1\x0\x0\xdd\x18\x0"
        "\x50\xf2\x1\x1\x0\x0\x50\xf2\x4\x1"
        "\x0\x0\x50\xf2\x4\x1\x0\x0\x50\xf2"
        "\x2\x0\x0"; /* stone beacon frame header */
/* adds the beacon frame */ 
memcpy(buf, type, sizeof(type));

/* adds the size marker */
memcpy(buf+sizeof(type), size, strlen(size));

/*adds the size number */
sprintf(messagelen, "%.5d", strlen(message));
memcpy(buf+sizeof(type)+strlen(size), messagelen, 5);

/* adds the message */
memcpy(buf+sizeof(type)+strlen(size)+sizeof(messagelen), message, strlen(message));

/* adds end marker */   
memcpy(buf+sizeof(type)+strlen(size)+sizeof(messagelen)+strlen(message), end, strlen(end));

The receiving end should be pretty straightforward if you are familiar with the pcap library. In receiver.c, pcap_loop is used to capture incoming packets and gets them processed by using got_packet, which is a callback function. This means that every time a packet gets captured it is passed to that function as a parameter. This function then subjects the packet to the following lines of code to determine if the packet meets our filter’s demands (i.e. having ‘stone’ as the SSID and having a valid size marker). When everything is in order, it will print the message sent by the server character by character.

/* drop everything that does not contain "x0\x11\x0\x0\x5\x73\x74\x6F\x6E\x65" */
identified = 0;
for (i = 0; i < 300; i++){
        if (identified == 0 && packet[i] == 's' && packet[i+1] == 't' && packet[i+2] == 'o' && packet[i+3] == 'n' && packet[i+4] == 'e'){
                identified = 1; 
        }       
}       
if (identified){
        /* looks for beginning of datastring and its size */ 
        start = 0;
        intlength = 0;
        for (i = 1; i < 1024; i++){
                if (start == 0 && packet[i] == 's' && packet[i+1] == 'i' && packet[i+2] == 'z' && packet[i+3] == 'e'){
                        start = i;
                }       
        }       
        if (start > 0){
                for (i = 0; i < 5; i++){
                        charlength[i] = packet[start+i+4];
                }       
                intlength = atoi(charlength);
        }       

        /* print output */
        if (intlength > 0){
                for (i = start+9; i <= start+9+intlength; i++){
                        fprintf(stdout, "%c", packet[i]);
                }       
        }       
}

To run the programs you must make sure of a couple of things. Firstly, make sure to have the proper permissions to use the wireless adapter. Secondly make sure that the wireless adapter(s) that you will be using is/are in monitor mode. And lastly that the transmitter and the receiver are using the same frequency (channel).

Running the program as root (or sudo) should take care of the permissions. If you are using the madwifi drivers you can do the following to get the wireless adapter into monitor mode. I am not sure on how to go about this with other drivers, but Google can probably help you with that.

Firstly bring the adapter down using:

$ ifconfig wlan0 down

Then do this to put the device in monitor mode:

$ iwconfig wlan0 mode monitor

Where wlan0 is your wireless adapter.

To change the channel of your device you can do:

$ iwconfig wlan0 channel 1

Or alternatively enter frequency manually:

$ iwconfig wlan0 freq 2.412G

Finally bring your adapter back online with:

$ ifconfig wlan0 up

If you did this for both the devices you are going to use, you should now be ready to successfully run the transmitter and receiver programs. After compiling the program you can run it by opening up two terminals, and running for example

$ ./transmitter wlan0

in one terminal, and

$ ./receiver wlan1

in the other. If you don’t have access to two wireless cards or you can’t be bothered to whip out another laptop or something you can also just run both programs using one adapter. This will however cause the receiver program to pick up and print all packets twice: once when it is broadcast and once when it is received.

You can now enter text in the transmitter program and once you press enter, it will be sent. You can also cat a text file and pipe its output into the program, this will send the contents of that file line by line.

$ cat file.txt | ./transmitter wlan1

Remember, not all packets might reach their destination and show up on the receiving side. There is no error checking involved. Also, the data is not encrypted. Anyone can just grab these packets out of the air. You could however implement these features yourself.

There are obvious advantages and disadvantages to using this method. An advantage might be how a technique like this could be implemented on any device that is capable of scanning for wireless networks. A disadvantage is that this would be very hard to scale.

As an example of what this can be used for, I created a program called beacontalk. Beacontalk is a simple peer to peer chat-program that re-broadcasts all incoming messages. This means that if there are three nodes, and node A can reach node B, and B can reach C, but node A can not reach C, then the message will get passed along by B to still reach all the nodes in the network.

You can get the source for beacontalk on github.

Permalink