Wednesday, June 29, 2016

Installing Oracle Express 11g using Docker on Ubuntu

Installation of Oracle database on a Linux system for learning purposes is a huge hassel since there are so many steps to follow to get Oracle database is up and running. Furthermore, since I'm running on Ubuntu Linux which is a Debian based system, things are much more complicated than working on a RPM based system. Due to these reasons, I was strugging to get Oracle databse up and running on my system for a while. Finally I found a nice way to use it. Without going through the overhead of installing it, I found a docker image which I can to directly run on my Ubuntu Linux platform. Following are the steps I followed to get it done on my Ubuntu 16.04 LTS system.

Preparing the system for Docker

These steps are needed if you didn't have docker configured in your system like me initially. I found these steps from here [1].

(1) Run following commands on the terminal.

sudo apt-get update
sudo apt-get install apt-transport-https ca-certificates
sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D


(2) Open the following file and remove any existing contents from it. In my case, I didn't have such a file anyway.

sudo vim /etc/apt/sources.list.d/docker.list

Add the following line to that file.

deb https://apt.dockerproject.org/repo ubuntu-xenial main

(3) Then run following commands.

sudo apt-get update
sudo apt-get purge lxc-docker
apt-cache policy docker-engine
sudo apt-get update
sudo apt-get install linux-image-extra-$(uname -r)


(4) Now let's install docker and start it. The last command is just to check whether docker works fine.

sudo apt-get update
sudo apt-get install docker-engine
sudo service docker start
sudo docker run hello-world


Setting up Oracle XE 11g in Docker

Now we are ready to get our oracle database running on docker. I found these instructions mainly from this [2] article.

(1) Let's pull the docker image from repository to our machine.

sudo docker pull alexeiled/docker-oracle-xe-11g

(2) We can start it with the following command.

sudo docker run -d -p 49160:22 -p 49161:1521 -p 49162:8080 alexeiled/docker-oracle-xe-11g

(3) We can see the status of the running docker container using the following commands.

# to see the running docker processes
sudo docker ps

# to see the things running inside a particular docker image, we can use the following command. The value we passed to the '-f' parameter is the contained ID which we can findout using the above command.

sudo docker logs -f 6ab14881419c

(4) We can get a bash terminal for our docker running Oracle XE using the following command. There also we have used the container ID as a parameter.

sudo docker exec -it 6ab14881419c /bin/bash

Preparing sqlplus tool for using Oracle XE 11g

Now that we have started running oracle xe as a docker image and got a root shell for this docker container, we can start interacting with the database server using the 'sqlplus' client program. Let's do some preliminary things to enable the sample database schema called HR and a user account to use it called HR account.

(1) Login to the database using 'sqlplus' tool with username 'system' and password 'oracle'.

# take the root shell of docker image
sudo docker exec -it 6ab14881419c /bin/bash

# start sqlplus tool
sqlplus

(2) Run the following query on the SQL prompt.

ALTER USER HR ACCOUNT UNLOCK IDENTIFIED BY password;

(3) We should see the output as 'User altered.' Now, 'exit' from the 'sqlplus' and then login again but this time with the unlocked user account where the username is 'system' and password is 'password'.

(4) Now in the SQL prompt, type the following query and see whether we get a proper output. If so, we have unlocked our HR account and the HR schema is now available to us.

select count(*) from employees;

Now we are good to go with learning Oracle database.

References:

[1] https://docs.docker.com/engine/installation/linux/ubuntulinux/

[2] http://tuhrig.de/3-ways-of-installing-oracle-xe-11g-on-ubuntu/

Sunday, June 26, 2016

Hands-on Minix3 microkernel based OS platform

Shell prompt of Minix3
Minix3 is a microkernel operating system which we can use to study how a microkernel is designed since its source code is open source. Before going into the internal details of Minix3, I installed it first on VMWare and moved around the shell prompt. Following are the steps I followed to install it.

(1) Download Minix3 from the official website. I downloaded the version 3.3.0 which was the stable release available by the time I download it.

(2) Using VMware Workstation, first I created a virtual machine without installing the operating system. When asked for the guest operating system and version, select the "other" option. For the disk capacity I selected 2GB and for RAM, I selected 512MB.

(3) After successfully creating the VM, we can attach the downloaded ISO image to the CD drive of the VM and then start it. We will be booted into a login prompt. Type root as the login name and enter. There's no password. When you get to the shell prompt, type  setup and enter to start the installation setup.

(4) During this installation setup, we will be set though various things such as keyboard selection, selecting hard disk partition, size of /home directory and block size for the hard disk. I basically went ahead with the default options on each of those prompts. Finally, the system will copy files to the installation hard disk partition. At the end of file copying, I was prompted to select the Ethernet device and I again went with the default option. Finally, I entered 'shutdown' to stop the installation system.

After the installation, there are some other things to do in the system if we wish. Let's boot the system and do some post-installation configurations.

(5) Power on the VM and login to the root account. There's no password yet for this account. Create a password for the root account using passwd command.

(6) From the root account, we can create a new user account which we can use to login later.

useradd -m asanka
passwd asanka

Logout from the root account and login from the newly created account to see whether it works. To log out from the system, exit command can be used.

(7) To check whether we have Internet access, we can ping to a known public IP address and see whether we get any response.

ping 8.8.8.8

To see our IP address, we can use the ifconfig command too.

(8) Update the package database as follows.

pkgin update

There are some default package set which we can install by issuing the following command.

pkgin_sets

(9) For writing programs, there are two important tools we need on an operating system. First is a text editor and the second is the compiler.

Our C compiler available on Minix3 by default is clang. There are some text editors available by default but I prefer vim. So, let's install it as follows.

pkgin update
pkgin install vim

To search for available packages, we can use the pkgin tool like the  following.

pkgin available | grep x11

Furthermore we can use the following command.

pkgin search x11

(10) Just like in Linux, we can switch between virtual terminals on Minix3 where we have 4 of them to switch between using Alt+F1 to Alt+F4.

(11) With our default packages, we get 'bash' package too. Therefore, we can use it from the terminal by typing bash on the prompt which then switch to the bash prompt which is more familiar and user friendly that the default shell.

References:

[1] http://wiki.minix3.org/doku.php?id=www:download:start


The visit of Dr. Shermin de Silva

Last Friday was  a busy day for me since I had two lectures to conduct one after the other from the morning. Firstly, it was Information security lecture from 8am to 10am and then it was Operating systems 2 lecture from 10am to 12pm. Luckily in the second lecture, Dr. Chamath was conducting the first half of the OS 2 lecture and therefore I was conducting a session just less than an hour. In the evening, I had a meeting with a final year student regarding the progress of his research project. Within this busy day with various activities, an important person visited our research group which was not ignorable. Therefore I decided to write a little note about this event.

Dr. Shermin de Silva (@Shermin_deSilva) is a well recognized ecologist who regularly visit Sri Lanka for her research projects based on Uda Walawe National Park regarding elephants. While working for the Smithsonian Institution in US, her activities for elephant conservation in Sri Lanka has made a great impact here. As we are working on few research projects related to human-elephant conflict, she was contacted by a one of our student members of the group who works on analyzing elephant infrasonic signals to locate them in the jungle. She was so happy to visit us and had a nice chat about the activities going on inside our group which relates to her work in the field. After having a short discussion in the lab, she joined with us for a lunch where we talked more about our work and future plans. She offered her help on various aspects of our future plans.

As a closing remark, I would like to share a talk Dr. Shermin has delivered in a TEDx event in 2012 where she talks about her passion towards elephant conservation.


Sunday, June 12, 2016

TUN/TAP devices on Linux

An interesting feature available on Linux is the ability to create virtual network interfaces. Usually we have different networking interfaces such as eth0 and wlan0 which directly maps to a network interface card available on our machine either wired or wireless. In addition to such real networking interfaces, we can create those virtual network interfaces so that our programs can communicate with such a networking interface just like it is communicating with a real networking interface.

There are two types of them. First type is TAP which represents an interface in layer 2 while the second type is TUN which represents a layer 3 interface which can be configured to have an IP address. We can have a user program which will read from and write to these TUN/TAP interfaces from the back end so that any software tool dealing with the virtual networking interface will feel like it is communicating with somebody over a network which the real communication occurs with the program running behind the TUN/TAP interface. This architecture can be illustrated as follows.

control program <--read/write--> TUN interface <--send/receive IP packets--> any networking program 

(1) Setting up a virtual TUN interface.

    # create a tun interface called 'asa0'
    sudo ip tuntap add dev asa0 mode tun

    # set an ip address
    sudo ip addr add 10.0.0.1/24 dev asa0

    # bring the interface up
    sudo ip link set dev asa0 up

    # let's see the settings now and then ping to our IP address of the TUN
    # interface
    ip addr show
    ping 10.0.0.1

    We should be able to see that ICMP responses are coming back when we ping to the correct IP address of the TUN interface. So, it is working. If we try to ping to any other IP address in the same network, we will not get any response.

    ping 10.0.0.2

    No response right? The packets destined to the same network are still directed to the newly created TUN network interface called asa0. But since this interface is virtual, there's nowhere to send these packet from the asa0 interface that's why we are not receiving any ping response back. That's fine. To get to know more clearly that all the packets for that network are directed to asa0 interface, we can check the routing table.

     route

My output looks like the below content. It is clear that the packets for the 10.0.0.0/24 network are directed to asa0 interface according to the routing table.

routing table
 That means, we are ready to use this TUN interface now.

(2) Open a text editor and write the following C program there. Save it with whatever the name you prefer. In my case, I saved it as tun-reader.c since this program opens the file descriptor of the TUN interface so that we can grab all the packets sent to the asa0 interface from the application layer.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <fcntl.h>  /* O_RDWR */
#include <string.h> /* memset(), memcpy() */
#include <stdio.h> /* perror(), printf(), fprintf() */
#include <stdlib.h> /* exit(), malloc(), free() */
#include <sys/ioctl.h> /* ioctl() */

/* includes for struct ifreq, etc */
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_tun.h>

int tun_open(char *devname)
{
    struct ifreq ifr;
    int fd, err;

    if ( (fd = open("/dev/net/tun", O_RDWR)) == -1 ) {
        perror("open /dev/net/tun");
        exit(1);
    }

    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TUN;
    strncpy(ifr.ifr_name, devname, IFNAMSIZ);

    /* ioctl will use if_name as the name of TUN
    * interface to open: "tun0", etc. */
    if ( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) == -1 ) {
        perror("ioctl TUNSETIFF");close(fd);exit(1);
    }

    /* After the ioctl call the fd is "connected" to tun device
    * specified
    * by devname */

    return fd;
}

int main(int argc, char *argv[])
{
    int fd, nbytes;
    char buf[1600];

    fd = tun_open("asa0") ;
    printf("Device asa0 opened\n");

    while(1) {
        nbytes = read(fd, buf, sizeof(buf));
        printf("Read %d bytes from asa0\n", nbytes);
    }
    return 0;
}

Compile the above program as follows.

gcc tun-reader.c

(3) Now we are ready to try our TUN interface with a back-end reading program. Let's start our tun-reader.c program which is now compiled into the executable called a.out.

./a.out

It will open the file descriptor of the asa0 interface and will wait for any packets. Let's send some packets to the asa0 interface as follows to see whether our program receive those packets.

ping 10.0.0.1

In the above case, we are pinging to the exact IP address of the asa0 interface. Therefore we receive ping responses from the interface directly without directing the ICMP packets to the back-end program. Now, let's ping to some other IP address in the same network.

ping 10.0.0.2

This time, you should see that the packets are now moving beyond the asa0 TUN interface and they are received by our back-end program. Our program will print the receiving packets as follows.

program output

Saturday, June 11, 2016

Pinging to a host using raw sockets

Raw sockets API is an interesting interface available on Unix-like operating systems to put our hands on network packets in their 'raw form' that includes the headers. Usually TCP and UDP sockets which we often use are a only giving us access to the payload of a transport layer datagram. But, there are times where we need to see the IP packet or may be the whole ethernet frame without loosing any content. Raw socket are the solution for this.

In the following example I'm presenting a simple ping-like program written in python that utilizes a raw socket to create the content of an IP packet with an ICMP payload.


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import socket
import sys
import time
from struct import pack, unpack

# checksum function
def checksum(msg):
    s = 0
    # loop taking 2 characters at a time
    for i in range(0, len(msg), 2):
        w = (ord(msg[i]) << 8) + (ord(msg[i+1]) )
        s = s + w

    s = (s>>16) + (s & 0xffff);
    #s = s + (s >> 16);
    #complement and mask to 4 byte short
    s = ~s & 0xffff
    return s

#create a raw socket
try:
    # this socket is to send custom made raw IP packets
    s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)

    # this socket is to receive ICMP packets
    s2 = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)

    print 'Sockets created'

except socket.error, msg:
    print 'Socket failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
    sys.exit()

#create a raw socket
try:
    # binding to the IP address configured to the network interface in my computer
    # through which I need to send and receive packets.
    s.bind(('10.22.220.239',0))
    s2.bind(('10.22.220.239',0))

    print 'Binding sockets was successful'

except socket.error, msg:
    print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
    sys.exit()

num_rounds = 1

while num_rounds:
    # creating a packet to send
    packet = ''
    source_ip = '10.22.220.239'
    dest_ip = '8.8.8.8' # or socket.gethostbyname('www.google.com')

    # ip header fields
    ip_ihl =5
    ip_ver = 4
    ip_tos = 0
    ip_tot_len = 0 #kernel will fill the correct total length
    ip_id = 54321 #Id of this packet
    ip_frag_off = 0
    ip_ttl = 255
    #ip_proto = socket.IPPROTO_TCP
    ip_proto = socket.IPPROTO_ICMP
    ip_check = 0 # kernel will fill the correct checksum
    ip_saddr = socket.inet_aton (source_ip) #Spoof the source ip address if you want to
    ip_daddr = socket.inet_aton (dest_ip)
    ip_ihl_ver = (ip_ver << 4) + ip_ihl

    # the ! in the pack format string means network order
    ip_header = pack('!BBHHHBBH4s4s', ip_ihl_ver, ip_tos, ip_tot_len, ip_id, ip_frag_off, ip_ttl, ip_proto, ip_check, ip_saddr, ip_daddr)

    ICMP_ECHO_REQUEST = 8

    # Header is type (8), code (8), checksum (16), id (16), sequence (16)
    #icmp_header = struct.pack('bbHHh', ICMP_ECHO_REQUEST, 0, 0, id, 1)
    icmp_header = pack('bbHHh', ICMP_ECHO_REQUEST, 0, 0, 1, 1)

    icmp_data = 192 * 'Q'
    # Calculate the checksum on the data and the dummy header.
    my_checksum = checksum(icmp_header + icmp_data)
    # Now that we have the right checksum, we put that in.
    # It's just easier
    # to make up a new header than to stuff it into the
    # dummy.
    #icmp_header = struct.pack('bbHHh', ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), id, 1)
    icmp_header = pack('bbHHh', ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), 1, 1)

    # final full packet
    packet = ip_header + icmp_header + icmp_data

    #Send the packet finally - the port specified has no effect
    s.sendto(packet, (dest_ip , 0 ))    # put this in a loop
    print 'sent a packet'
    #---------------------------------------------------------------------------
    # receive a packet
    packet = s2.recvfrom(65565)

    #packet string from tuple
    packet = packet[0]

    #take first 20 characters for the ip header
    ip_header = packet[0:20]

    #now unpack them :)
    iph = unpack('!BBHHHBBH4s4s', ip_header)

    version_ihl = iph[0]
    version = version_ihl >> 4
    ihl = version_ihl & 0xF

    iph_length = ihl * 4
    ttl = iph[5]
    protocol = iph[6]
    s_addr = socket.inet_ntoa(iph[8])
    d_addr = socket.inet_ntoa(iph[9])

    print 'received a packet'
    print 'Version : ' + str(version) + ' IP Header Length : ' + str(iph_length) + ' TTL : ' + str(ttl) + ' Protocol : ' + str(protocol) + ' Source Address : ' + str(s_addr) + ' Destination Address : ' + str(d_addr)

    time.sleep(1)
    #num_rounds = 0

Perhaps I would write a more comprehensive blog post about how to use raw sockets. Anyway, everything depends on whether I can spend an enough time on such an exercise. Anyway, let's see. Until then, that's all folks!