Setting up VNC as Teamviewer alternative

Teamviewer is sometimes really annoying. It has a lot of bugs, crashes very often and doesn’t have a native application for Linux(uses wine…. yewww). Chrome Remote Desktop is nice but it doesn’t allow long term password based connections on Linux. So I resorted to VNC. There is a common conception that setting up VNC is very hard. In this post, I will try to make the process simple.

Setting up the server

Setting up reverse SSH

In most cases the Remote machine is behind a firewall or has dynamic IP address. This makes it impossible to connect the remote machine from the internet. So we will first setup a secure tunnel between Middle server and Remote server. Once this is setup, we can access the Remote machine through the Middle server. The Middle server will always have static IP and is accessible though the internet.


Install SSH on Middle server

sudo apt-get install openssh-server openssh-client

We have to set a few configuration options in /etc/ssh/sshd_config. Add the following flags or modify them if they already exist in the config file:

ClientAliveInterval 30
ClientAliveCountMax 99999
GatewayPorts yes
AllowTcpForwarding yes
TCPKeepAlive yes

The SSH server has to be restarted for the configuration changes to take effect:

sudo service ssh restart

Install SSH on Remote machine

sudo apt-get install openssh-server openssh-client

From Remote machine establish a SSH reverse tunnel to Middle server,

ssh -nNT -R ssh_tunnel_port:localhost:22 middle_server_username@middle_server_ipaddress

Now you should be able to connect to Remote machine from your client machine using the command,

ssh remote_username@middle_server_ipaddress -p ssh_tunnel_port

Setting up x11vnc in Remote machine

On the Remote machine, install x11vnc and start vnc server on display :0

sudo apt-get install x11vnc
sudo x11vnc -forever -display :0 -auth /home/remote_username/.Xauthority

Setting up client

Tunnel VNC port to client machine


Linux & MacOS

ssh -t -L 5900:localhost:5900 remote_username@middle_server_ipaddress -p ssh_tunnel_port

Windows & Linux & MacOS

You can also use putty to tunnel ports. Download and install Putty from this link.



View the remote desktop

You can use this cross-platform chrome extension to view the remote desktop. In the address field provide localhost:5900 and click Connect.

Waspmote v1.1: Installing IDE and development environement

In this article, we will install the waspmote IDE and necessary development environment.

Download and Install Waspmote IDE

Currently there are two versions of Waspmotes available(v1.1 and v1.2). If you don’t want to break your head trying to debug why you cannot upload the sketch to board, download the correct IDE (:p) from this link.

If you get the following error during upload, you have the wrong IDE installed.

avrdude: Send: 0 [30] [20]
avrdude: Send: 0 [30] [20]
avrdude: Send: 0 [30] [20]
avrdude: Recv: . [00]
avrdude: stk500_getsync(): not in sync: resp=0x00

avrdude done. Thank you.

Extract the downloaded archive into a suitable directory and fire up the waspmote script present inside it.


Install avr-gcc compiler tool chain

To make things more complicated, the latest version of gcc-avr package in the Ubuntu repositories are not backward compatible with the old v1.1 waspmote IDE. So when you try to compile or verify the sketch, you will get the following error:

avr-gcc: error: unrecognized command line option ‘-assembler-with-cpp’

The fix is to remove the latest gcc-avr package and install the old version of it manually. Execute this command to remove the latest packages:

sudo apt-get remove avr-libc gcc-avr

Download the following packages and install them manually by double clicking them.

  1. gcc-avr 4.5.3-3
  2. avr-libc 1.7.1-2

Install 32-bit version of libusb

Latest versions of Waspmote IDE uses 64-bit version of avrdude binary by default on 64-bit machines. But the old v1.1 IDE uses 32-bit version. So we have to install 32-bit version of libusb.

sudo apt-get install libusb-0.1-4:i386

Now you have the IDE and the development environment set up. Try to compile and upload the hello_world or test sketch.

Changing MAC address using c/c++ in linux

Here is a small code snippet that can be used to change MAC address in linux.

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if_arp.h>
#include <net/if.h>

int main(int argc, char **argv) {
	struct ifreq ifr;
	int s;
	char mac_char[] = "12:34:56:78:12:34";

	sscanf(mac_char, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",

	s = socket(AF_INET, SOCK_DGRAM, 0);
	assert(s != -1);

	strcpy(ifr.ifr_name, "eth0");
	ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
	assert(ioctl(s, SIOCSIFHWADDR, &ifr) != -1);


Note: This application should be given root access to be able to change MAC address.

witnessing ip fragmentation using ping

My friend was testing ip fragmentation attacks on linux. So we had to witness ip fragmentation effect first. As we know, an IP packet can carry a total packet length of 65535(2^16 – 1) bytes. But since, data link layer(ethernet) frames can only carry maximum data size of 1500(MTU) bytes, IP has to fragment the packet if its length is greater than MTU. Out of 1500 bytes, IP’s header will itself occupy 20 bytes. We are left with 1480 bytes of data. Since we are using ping(which internally uses ICMP), 8 bytes are used by ICMP for its header.  We are left with 1472 bytes, which is the maximum data size that can be sent using ping.

Fig1 Ethernet frame format

ip packet format
Fig2 IP packet format

Fig3 ICMP frame format

Note: To check MTU of interface eth0, type

ifconfig eth0

This is the ip we will be using throughout this test,


Run tcpdump in another terminal to keep track of transmission,

tcpdump -i wlan0 icmp -vvv

Now let us test the connection,

ping $EXIP -s 1472 -c 1

tcpdump reports that the packet has been sent,

01:58:05.960968 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 1500)
teja-laptop.local > vinit-PC.local: ICMP echo request, id 15530, seq 1, length 1480

When we try to send a packet with packet size greater than MTU and don’t fragment flag set,

ping $EXIP -s 1473 -M do -c 1

tcpdump remains silent because no packets are being sent. Lets see the output of ping and infer what has happened,

PING ( 1473(1501) bytes of data.
From icmp_seq=1 Frag needed and DF set (mtu = 1500)

— ping statistics —
0 packets transmitted, 0 received, +1 errors

This shows that if we try to send a packet with size greater than MTU and don’t fragment bit set, ping replies that it can’t send the packet. Now let us try to send the same packet with don’t fragment bit unset,

ping $EXIP -s 1473 -c 1

02:02:33.141005 IP (tos 0x0, ttl 64, id 31043, offset 0, flags [+], proto ICMP (1), length 1500)
teja-laptop.local > vinit-PC.local: ICMP echo request, id 15540, seq 1, length 1480
02:02:33.141134 IP (tos 0x0, ttl 64, id 31043, offset 1480, flags [none], proto ICMP (1), length 21)
teja-laptop.local > vinit-PC.local: icmp

Voila! The packet has been fragmented. As you can see, IP layer has fragmented the packet into two fragments. The first fragment has offset 0, id 31043 and length 1500. The second packet has the same id as the first but the offset shows where exactly this fragment fits into in the original packet. The data length of second packet is only 21(IP header + remaining 1 byte). Finally “flags [+]” in first packet means that there are more fragments yet to arrive while “flags [none]” in second packet means this is the last fragment.