Thursday, April 28, 2011

Introduction to RPKI

What is RPKI

Resource Public Key Infrastructure (RPKI) is the name of the game.
For the Internet to work, we need BGP1 which in turn requires IP prefixes and AS numbers.  When an LIR or any multi homed organization wants to be reachable on the Internet, they have to peer using these number resources.

No security framework exists that authenticates whether a peer does indeed own the resource set that they are advertising. Consequently, rogue announcements2 may appear on the internet that will impact on the reachability of legitimate sites. RPKI allows one to take these resources, add them into a certificate and then use these resource aware certificates to sign Route Origin Authorizations (ROA) and a set of other objects that may be defined in the future (The underlying specification documents are still in draft status For the latest and up to date specifications, please see the sidr ietf page).

Number resources are issued by IANA to the 5 RIRs. These RIRs then issue resources to LIRs/NIRs which issue their resources to their customers. Their customers may issue their resources... PKIs do follow a similar tree structure where there's a root (self signed CA certificate) issues other certificates (Which may be CA certificates that subissue ...). Consequently, every resource owner can and should have a resource certificate.


These two hierarchical structures are similar and this allows them to be tightly integrated.

An example allocation structure:


Table 1: Resource Allocation table
ORG IPV4 IPV6 ASN Function
IANA 0/0 0/0 1-2**32 Issues resources to RIRS
AFRINIC 196/8 2001:4200/23 327680-328703 Issues resources to LIRS
LIR C 196.1/16 2001:4200/32 327680-327690 Large ISP.
ISP X 196.1.0/23 2001:4200/48 327685 Small ISP.

An example PKI structure:

What is RPKI...Really?

Well:
  • It allows a resource holder to prove that they do actually owns a set of resources (Binds number resources to the subject of the certificate).
  • A resource holder can provide a PKI based authorisation attesting that a peer is allowed to originate a set of prefixes on their behalf (In simple terms, I am a small company X who buys bandwidth with A & C. A ROA can be created to attest that only A & C can advertise X's prefixes)
  • CRLs are also published and their distribution points listed in certificates.
  • Certificates, CRLs and products such as ROAs for each authority publication point are listed along with their hashes in a signed structure that is published. This structure is called a manifest(mft).
  • CA certs, CRLs, MFTs, ROAs are published in a repository to the world over rsync and optionally https.
  • Validation tools exist that can validate an entire repository tree
Next, A quick peek at sample RPKI certificates.

Thursday, April 21, 2011

XMLRPC Register instance is stateful. Do not want that

I have an XMLserver that uses the method SimpleXMLRPCServer.register_instance to register a class and it's methods. Something like:
....    
    inst = ServiceClass(init_params)
    server.register_instance(inst)
    server.register_introspection_functions()

    try:
        server.serve_forever()
    finally:
        server.server_close()
The serviceclass looks like:
class ServiceClass(object):
    """ServiceClass calls the xxxx executable and returns stdout & stderr"""
    def __init__(self, params):
        super(ServiceClass, self).__init__()
        self.params = params
        print "Init with %s" % self.params

    def _shell_exec(self, cmd=[]):
        .......
        ....
...
    def dbupdate(self, sometext=""):
        """Given an object, try call the xxxx binary and
        return the output of the command
        Keyword arguments:                                                                                                                 
        params:                                                                                                                            
            sometext -- text of the object
        """
        if not len('sometext'):
            raise MissingObjectError("No text passed for command")

        # Create a tempfile
        (tmpfd, fname) = tempfile.mkstemp()
        os.write(tmpfd,  sometext)
        os.close(tmpfd)
        # Execute
        cmd_exe = self.params['cmd']                                                                                                       
        cmd_exe.extend([fname])
        ret_stdout, ret_stderr = self._shell_exec(cmd_exe)

        # Cleanup file
        os.unlink(fname)

        print "cmd: %s\nself.cmd: %s\nfname: %s\n" %(cmd_exe, self.params['cmd'], fname)
    
        return (ret_stdout, ret_stderr)
Turns out that python keeps state since... the instance is created only once at server startup. All subsequent calls share this instance. And that affects the class variables. Notice that tempfiles from a prior run are visible to a later run which might be from a different client. :(
:!python some_webservice_xmlrpc.py -d 1 -p 8000                                                                                        
Listening on :8000...
Service URI is http://:8000/
Use Control-C to exit
CMD: ['/path/to/executable', '-c', '/path/to/config.conf', '-f', '/tmp/tmpkCXRS-']
cmd: ['/path/to/executable', '-c', '/path/to/config.conf', '-f', '/tmp/tmpkCXRS-']
self.cmd: ['/path/to/executable', '-c', '/path/to/config.conf', '-f', '/tmp/tmpkCXRS-']
fname: /tmp/tmpkCXRS-

machine1.example.net - - [21/Apr/2011 14:53:08] "POST / HTTP/1.0" 200 -
CMD: ['/path/to/executable', '-c', '/path/to/config.conf', '-f', '/tmp/tmpkCXRS-', '/tmp/tmpBGDHHU']
cmd: ['/path/to/executable', '-c', '/path/to/config.conf', '-f', '/tmp/tmpkCXRS-', '/tmp/tmpBGDHHU']
self.cmd: ['/path/to/executable', '-c', '/path/to/config.conf', '-f', '/tmp/tmpkCXRS-', '/tmp/tmpBGDHHU']
I tried different solutions from del cmd prior to return to initializing all variables to None|"" at the start of the method. Didn't work.. till I remembered shallow copying.   With a deep copy,
....                                                   
#        cmd_exe.extend([fname])
#Replace with
        cmd_exe = copy.deepcopy(self.params['cmd'])
....
things behave as expected:
Listening on :8000...
Service URI is http://:8000/
Use Control-C to exit
Init with {'debug': 1, 'cmd': ['/path/to/executable', '-c', '/path/to/config.conf', '-f']}
CMD: ['/path/to/executable', '-c', '/path/to/config.conf', '-f', '/tmp/tmpLTR0-S']
cmd: ['/path/to/executable', '-c', '/path/to/config.conf', '-f', '/tmp/tmpLTR0-S']
self.cmd: ['/path/to/executable', '-c', '/path/to/config.conf', '-f']
fname: /tmp/tmpLTR0-S

machine1.example.net - - [21/Apr/2011 14:58:19] "POST / HTTP/1.0" 200 -
CMD: ['/path/to/executable', '-c', '/path/to/config.conf', '-f', '/tmp/tmpxdCOtw']
cmd: ['/path/to/executable', '-c', '/path/to/config.conf', '-f', '/tmp/tmpxdCOtw']
self.cmd: ['/path/to/executable', '-c', '/path/to/config.conf', '-f']
fname: /tmp/tmpxdCOtw

machine1.example.net - - [21/Apr/2011 14:58:26] "POST / HTTP/1.0" 200 -

Friday, April 15, 2011

recursion && tail recursion

A look at the difference between plain old recursion and tail recursion.
$ gdb recursion
GNU gdb (GDB) 7.2-debian
.....
(gdb)
  • Set up breakpoints at recursion termination points
(gdb)  break recursion.c:50
Breakpoint 1 at 0x4005b9: file /home/lmwangi/learning/algo/recursions/recursion.c, line 50.
(gdb)  break recursion.c:68
Breakpoint 2 at 0x400601: file /home/lmwangi/learning/algo/recursions/recursion.c, line 68.
  • Run till the first breakpoint - Good old recursion. Notice that we have to step 4 times.
(gdb) run
Starting program: /home/lmwangi/learning/algo/recursions/recursion

Breakpoint 1, factorial (n=1) at /home/lmwangi/learning/algo/recursions/recursion.c:50
50                      return 1;
(gdb) bt
#0  factorial (n=1) at /home/lmwangi/learning/algo/recursions/recursion.c:50
#1  0x00000000004005cd in factorial (n=2) at /home/lmwangi/learning/algo/recursions/recursion.c:53
#2  0x00000000004005cd in factorial (n=3) at /home/lmwangi/learning/algo/recursions/recursion.c:53
#3  0x00000000004005cd in factorial (n=4) at /home/lmwangi/learning/algo/recursions/recursion.c:53
#4  0x00000000004005cd in factorial (n=5) at /home/lmwangi/learning/algo/recursions/recursion.c:53
#5  0x0000000000400544 in main () at /home/lmwangi/learning/algo/recursions/recursion.c:30
(gdb) step
56      }
(gdb) step
56      }
(gdb) step
56      }
(gdb) step
56      }
(gdb) step
56      }
(gdb) step
main () at /home/lmwangi/learning/algo/recursions/recursion.c:32
32              printf("Factorial %d\n", result);

  • Tail recursion. Notice that we step only once since the function has all the results from prior operations
(gdb) cont
Continuing.
Factorial 120

Breakpoint 2, tail_factorial (n=1, a=120) at /home/lmwangi/learning/algo/recursions/recursion.c:68
68                      return a;
(gdb) bt
#0  tail_factorial (n=1, a=120) at /home/lmwangi/learning/algo/recursions/recursion.c:68
#1  0x000000000040061c in tail_factorial (n=2, a=60) at /home/lmwangi/learning/algo/recursions/recursion.c:71
#2  0x000000000040061c in tail_factorial (n=3, a=20) at /home/lmwangi/learning/algo/recursions/recursion.c:71
#3  0x000000000040061c in tail_factorial (n=4, a=5) at /home/lmwangi/learning/algo/recursions/recursion.c:71
#4  0x000000000040061c in tail_factorial (n=5, a=1) at /home/lmwangi/learning/algo/recursions/recursion.c:71
#5  0x000000000040056d in main () at /home/lmwangi/learning/algo/recursions/recursion.c:34
(gdb) step
73      }
(gdb) step
main () at /home/lmwangi/learning/algo/recursions/recursion.c:36
36              printf("Tail Factorial %d\n", result);
(gdb)
 

Unix Permission modes

This is a long post covering unix permission modes. A file's mode is stored in it's inode structure. Most of this post is inline in the following shell interaction snippet(plain text here). The quirky bits are:
  1. Permissions are analysed in increasing generality i.e User, Group, Others. The first match is accepted whether positive or negative
  2. Executing a setuid binary is equivalent to executing that binary as the user owning the binary
  3. Executing a setgid binary is equivalent to executing the binary as the group owning that binary
  4. Binaries require setting the x bit only while shell scripts require r & x bits to be set.
  5. If you setgid a directory and create a file in that directory, the file's group will be set to the group of the directory (Group permissions become inherited regardless of whether you were in that group).
  6. Sticky bits on a directory restrict deletion to the owner of the directory, the creator of a file and the superuser. That's how /tmp works! It's also known as the restricted deletion flag.

# Lets make a couple of tests
$ test_read () { $(cat  2>/dev/null test.file > /dev/null ); if [ $? -eq 0 ];then echo "Read : True "; else echo "Read : False"; fi; }
$ test_write () { $(echo 2>/dev/null -e '#!/bin/sh\necho hello' > test.file ); if [ $? -eq 0 ];then echo "Write: True "; else echo "Write: False"; fi; }
$ test_exec () { $( ./test.file 2>/dev/null 1>/dev/null); if [ $? -eq 0 ];then echo "Exec : True "; else echo "Exec : False"; fi; }

# Touch a test.file
$ ls -l test.file
-rwx------ 1 lmwangi lmwangi 21 Apr 14 16:31 test.file

# Test mode as user 
$ for mode in $(seq -w 0 100 700); do echo "Mode $mode"; touch test.file; chmod $mode test.file; test_read; test_write; test_exec;echo;  done
Mode 000
Read : False
Write: False
Exec : False

Mode 100
Read : False
Write: False
Exec : False

Mode 200
Read : False
Write: True 
Exec : False

Mode 300
Read : False
Write: True 
Exec : False

Mode 400
Read : True 
Write: False
Exec : False

Mode 500
Read : True 
Write: False
Exec : True 

Mode 600
Read : True 
Write: True 
Exec : False

Mode 700
Read : True 
Write: True 
Exec : True 


# File permissions like firewall acls stop at the first match. If I am the owner of the file, matching stops with the user bits. Groups/others are never consulted... So we chgrp of file to a group you are not in say root and test.
$ sudo chgrp root test.file 
$ ls -l
total 4
----rwx--- 1 lmwangi root 21 Apr 14 16:36 test.file

$ for mode in $(seq -w 0 010 070); do echo "Mode $mode"; touch test.file; chmod $mode test.file; test_read; test_write; test_exec;echo;  done
Mode 000
Read : False
Write: False
Exec : False

Mode 010
Read : False
Write: False
Exec : False

Mode 020
Read : False
Write: False
Exec : False

Mode 030
Read : False
Write: False
Exec : False

Mode 040
Read : False
Write: False
Exec : False

Mode 050
Read : False
Write: False
Exec : False

Mode 060
Read : False
Write: False
Exec : False

Mode 070
Read : False
Write: False
Exec : False

# It get's interesting if I am not the owner of the file but I am in a group that owns the file.
$ id
uid=1000(lmwangi) gid=1000(lmwangi) groups=1000(lmwangi),20(dialout),24(cdrom),25(floppy),29(audio),44(video),46(plugdev),112(netdev),114(fuse),119(libvirt),1003(packetcapture)
$ ls -l
total 4
----rwx--- 1 root lmwangi 21 Apr 14 16:42 test.file

for mode in $(seq -w 0 010 070); do echo "Mode $mode"; sudo chmod $mode test.file; test_read; test_write; test_exec;echo;  done
Mode 000
Read : False
Write: False
Exec : False

Mode 010
Read : False
Write: False
Exec : False

Mode 020
Read : False
Write: True 
Exec : False

Mode 030
Read : False
Write: True 
Exec : False

Mode 040
Read : True 
Write: False
Exec : False

Mode 050
Read : True 
Write: False
Exec : True 

Mode 060
Read : True 
Write: True 
Exec : False

Mode 070
Read : True 
Write: True 
Exec : True 

# The same principle applies. Others mode only applies if I am neither the file owner nor in a group that owns the file.
$ for mode in $(seq -w 0 001 007); do echo "Mode $mode"; sudo chmod $mode test.file; test_read; test_write; test_exec;echo;  done
Mode 000
Read : False
Write: False
Exec : False

Mode 001
Read : False
Write: False
Exec : False

Mode 002
Read : False
Write: True 
Exec : False

Mode 003
Read : False
Write: True 
Exec : False

Mode 004
Read : True 
Write: False
Exec : False

Mode 005
Read : True 
Write: False
Exec : True 

Mode 006
Read : True 
Write: True 
Exec : False

Mode 007
Read : True 
Write: True 
Exec : True 

# It gets better with executables :)
# Let's make a small template executable
$  echo -e '#include <stdio.h>\nint main(){printf("hello\\n"); return 0;}' > hello.c && gcc hello.c -o hello
$ ./hello 
hello
# Now watch mode 100 compare with the a shell script of mode 100. Do the same for 300, 500 & 700
Mode 000
Read : False
Write: False
Exec : False

Mode 100
Read : False
Write: False
Exec : True 
Mode 200
Read : False
Write: True 
Exec : False

Mode 300
Read : False
Write: True 
Exec : True 

Mode 400
Read : True 
Write: False
Exec : False

Mode 500
Read : True 
Write: False
Exec : True 

Mode 600
Read : True 
Write: True 
Exec : False

Mode 700
Read : True 
Write: True 
Exec : True 

# As can be seen. You must have r & x to exec a shell script while your require only x for a binary.
# Recap again
$ for mode in $(seq -w 0 100 700); do echo $mode; chmod $mode test.file; ls -l test.file |grep test.file; ./test.file; done
000
---------- 1 lmwangi lmwangi 6695 Apr 14 17:06 test.file
-bash: ./test.file: Permission denied
100
---x------ 1 lmwangi lmwangi 6695 Apr 14 17:06 test.file
hello
200
--w------- 1 lmwangi lmwangi 6695 Apr 14 17:06 test.file
-bash: ./test.file: Permission denied
300
--wx------ 1 lmwangi lmwangi 6695 Apr 14 17:06 test.file
hello
400
-r-------- 1 lmwangi lmwangi 6695 Apr 14 17:06 test.file
-bash: ./test.file: Permission denied
500
-r-x------ 1 lmwangi lmwangi 6695 Apr 14 17:06 test.file
hello
600
-rw------- 1 lmwangi lmwangi 6695 Apr 14 17:06 test.file
-bash: ./test.file: Permission denied
700
-rwx------ 1 lmwangi lmwangi 6695 Apr 14 17:06 test.file
hello


# Now let's look at the  setuid/setgid/sticky bits. 
1 = Sticky - if set not relevant in a binary in my system [Linux]
2 = SetGID - if set the progran runs with eGID set to the binary group
4 = SetUID - if set the program runs with euid set tot the binary owner.

# Let's make a program that shows us the uid, effective uid, gid and effective gid
$ echo -e '#include <stdio.h>\n#include <unistd.h>\nint main(){printf("hello\\nUID:%d\\nEUID:%d\\nGID:%d\\nEGID:%d\\n",getuid(),geteuid(),getgid(),getegid()); return 0;}' > hello.c && gcc hello.c -o hello                                                      

$ ./hello 
hello
UID:1000
EUID:1000
GID:1000
EGID:1000

$ id
uid=1000(lmwangi) gid=1000(lmwangi) groups=1000(lmwangi),20(dialout),24(cdrom),25(floppy),29(audio),44(video),46(plugdev),112(netdev),114(fuse),119(libvirt),1003(packetcapture)

$ for owner in lmwangi:lmwangi lmwangi:root root:lmwangi root:root; do echo ">>>> $owner <<<<"; for mode in 1777 2777 4777 6777; do echo "mode $mode"; cp hello test.file ; sudo chown $owner test.file; sudo chmod $mode test.file; ls -l test.file; ./test.file;echo; done;  done
>>>> lmwangi:lmwangi <<<<
mode 1777
-rwxrwxrwt 1 lmwangi lmwangi 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:1000
GID:1000
EGID:1000

mode 2777
-rwxrwsrwx 1 lmwangi lmwangi 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:1000
GID:1000
EGID:1000

mode 4777
-rwsrwxrwx 1 lmwangi lmwangi 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:1000
GID:1000
EGID:1000

mode 6777
-rwsrwsrwx 1 lmwangi lmwangi 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:1000
GID:1000
EGID:1000

>>>> lmwangi:root <<<<
mode 1777
-rwxrwxrwt 1 lmwangi root 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:1000
GID:1000
EGID:1000

mode 2777
-rwxrwsrwx 1 lmwangi root 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:1000
GID:1000
EGID:0

mode 4777
-rwsrwxrwx 1 lmwangi root 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:1000
GID:1000
EGID:1000

mode 6777
-rwsrwsrwx 1 lmwangi root 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:1000
GID:1000
EGID:0

>>>> root:lmwangi <<<<
mode 1777
-rwxrwxrwt 1 root lmwangi 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:1000
GID:1000
EGID:1000

mode 2777
-rwxrwsrwx 1 root lmwangi 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:1000
GID:1000
EGID:1000

mode 4777
-rwsrwxrwx 1 root lmwangi 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:0
GID:1000
EGID:1000

mode 6777
-rwsrwsrwx 1 root lmwangi 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:0
GID:1000
EGID:1000

>>>> root:root <<<<
mode 1777
-rwxrwxrwt 1 root root 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:1000
GID:1000
EGID:1000

mode 2777
-rwxrwsrwx 1 root root 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:1000
GID:1000
EGID:0

mode 4777
-rwsrwxrwx 1 root root 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:0
GID:1000
EGID:1000

mode 6777
-rwsrwsrwx 1 root root 7205 Apr 14 17:31 test.file
hello
UID:1000
EUID:0
GID:1000
EGID:0

# Sticky bit (RESTRICTED DELETION FLAG) on directories 

$ mkdir test; sudo chown root:root test; sudo chmod 1777 test; ls -l |grep test
drwxrwxrwt 2 root    root    4096 Apr 14 17:39 test
-rwsrwsrwx 1 root    root    7205 Apr 14 17:31 test.file

$ echo lmwangi > test/by_lmwangi
$ ls -l test/
total 4
-rw-r--r-- 1 lmwangi lmwangi 8 Apr 14 17:41 by_lmwangi

# No one can remove the file
$ sudo su guest -c "rm test/by_lmwangi"
rm: remove write-protected regular file `test/by_lmwangi'? y
rm: cannot remove `test/by_lmwangi': Operation not permitted

# Root can  override though or the owner of the dir
$ sudo rm test/by_lmwangi 

$ rm -rf test
$ mkdir test
$ chmod 1777 test
$ sudo su guest -c "echo hello > test/by_guest"
$ ls -l test
total 4
-rw-r--r-- 1 guest guest 6 Apr 14 17:38 by_guest
$ ls -l |grep test
drwxrwxrwt 2 lmwangi lmwangi 4096 Apr 14 17:38 test
-rwsrwsrwx 1 root    root    7205 Apr 14 17:31 test.file
$ cat test/by_guest 
hello
$ rm test/by_guest 
rm: remove write-protected regular file `test/by_guest'? y

$ ls -l test
total 0

# And we go out with a bang
# setuid on dir == no change on files                                                                  
$ rm -rf test && mkdir test; sudo chown root:root test; sudo chmod 4777 test; ls -l|grep test
$ cd test/
$ touch aha
$ ls -l
total 0
-rw-r--r-- 1 lmwangi lmwangi 0 Apr 14 17:46 aha
$ cd ..

# But setgid on dir == changes any file created in it to the group owning the dir
$ rm -rf test && mkdir test; sudo chown root:root test; sudo chmod 2777 test; ls -l|grep test
drwxrwsrwx 2 root    root    4096 Apr 14 17:47 test
-rwsrwsrwx 1 root    root    7205 Apr 14 17:31 test.file
$ cd test/
$ touch aha
$ ls -l
total 0
-rw-r--r-- 1 lmwangi root 0 Apr 14 17:47 aha
$ id
uid=1000(lmwangi) gid=1000(lmwangi) groups=1000(lmwangi),20(dialout),24(cdrom),25(floppy),29(audio),44(video),46(plugdev),112(netdev),114(fuse),119(libvirt),1003(packetcapture)

Unix is loads of fun :)