To the infinty… and beyond!

Python Port Locker/unlocker

| Comments

If you run you own server (VPS, cloud instances, bare metal, no matter what), I guess you check your log files almost on daily basis, and probably you already run any the multiple available tools (the list is pretty long, but in my case I use logwatch) that helps you out to keep an eye in what is going on in your machine.

There is one thing in particular that drives me crazy. As soon as you expose a machine to the internet, people will be constantly trying to get SSH access:

Obviously, there are tools that will make your life easier (like fail2ban, totally recommended) and some security tweaks (just Google for “linux server hardening”) that you should be doing if you manage your own server, but even with all those things in place, I really don’t like people trying to access to my server 24/7… Call me crazy, if you like.

A simple solution would have been just to change the SSH port to a something different, like 22222, and this might work for you. Unfortunately, I spend most of the time behind a proxy server, and I can only access the most common ports (the same very ones that are scanned on regular basis), so I needed to keep ssh service running in port 22.

Last year I coded a small bash script (just for myself) that allowed me to open and close SSH port on demand. It is been working fine since then, and I don’t get annoyed by the ssh auth errors in logwath anymore. Now I migrated it to Python, and I thought it could be useful for anyone else, so here it is…

The script is not big deal, it will open/close certain ports that I preconfigured by reading a text file. Nothing new under the sun.

The only “particularity” of this script is that, instead of creating a service (webservice??) that allowed me to send the desired ssh state to the server (this would add another “attack vector”), I decided the script would pull the data from another location. I decided to use a (public) file in my dropbox folder.

If you want it to give it a try, these are the steps:

1 - Create a file in your dropbox folder and get the public link. Let’s say that you get something like this:

1
https://www.dropbox.com/s/XXXXXXXXXXXXXXXX/file

2 - Add to this file any of the options you defined in the script. ie:

1
2
3
open ssh
close vpn
open  httpd

3 - Upload this script to your server (github link available in the code snippet header):

portLocker.pylink
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
#!/usr/bin/env python
#===============================================================================
#
#          FILE:  portLocker.py
#         USAGE:  python portLocker.py
#   DESCRIPTION:  port blocker/unblocker via dropbox file
#        AUTHOR:  http://bynario.com
#       CREATED:  05/08/2014 17:37:23 CEST
#===============================================================================
import time,sys,os,subprocess

dbFile="https://www.dropbox.com/s/XXXXXXXXXXXXXXXX/file"
logFile="/var/log/locker_log.log"
htmlFile="/usr/share/nginx/www/sshd.html"
servicesL={'ssh':'22','vpn':'1723','httpd':'80'}
actionsL=('open','close')

def createWWW(filename):
    try:
        with open(filename, 'w') as f: f.write(getTime())
    except Exception as e:
        print2Log(logFile,"Error opening "+filename+": "+str(e))

def print2Log(filename,text):
    try:
        with open(filename, 'w') as f:
            f.write(getTime() + " - " + text+"\n")
    except Exception as e:
        print2Log(logFile,"Error opening "+filename+": "+str(e))

def print2WWW(filename,service,status):
    try:
        with open(filename, 'a') as f:
            f.write(" - Service: " + service + " - Status: " + status)
    except Exception as e:
        print2Log(logFile,"Error opening "+filename+": "+str(e))

def getTime():
    return time.strftime("%Y-%m-%d %H:%M")

def runCommand(command,retVal=None):
    try:
        p = subprocess.Popen(command.split(), stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=False)
        (output, err) = p.communicate()
        if retVal: return output
        else: return None
    except Exception as e:
        print2Log(logFile,"Error executing "+str(command)+": "+str(e))

def checkDBFile():
    action="/usr/bin/curl -s -L " + dbFile
    command=runCommand(action,retVal=True)
    return command

def runIptables(service,action):
    print getTime() + " Running iptables... Service: " + service + " Action:" + action
    check_command="/sbin/iptables -C INPUT -p tcp -m tcp --dport " + servicesL[service] +" -j DROP"
    try:
        check_output = subprocess.check_call(check_command.split(),stderr=subprocess.STDOUT)
    except subprocess.CalledProcessError as e:
        if action == "close": command="/sbin/iptables -A INPUT -p tcp --dport " + servicesL[service] + " -j DROP"
        else: return
    else:
        if action == "open": command="/sbin/iptables -D INPUT -p tcp --dport " + servicesL[service] + " -j DROP"
        else: return

    runCommand(command)

if __name__ == "__main__":
    createWWW(htmlFile)

    for line in checkDBFile().splitlines():
        if not line: continue
        if len(line.split()) != 2:
            print2Log(logFile,"Error in dropbox file: wrong format")
            sys.exit(1)
        else:
            act = line.split()[0]
            serv = line.split()[1]

            if servicesL.has_key(serv) and act in actionsL:
                runIptables(serv,act)
                print2WWW(htmlFile,serv,act)
            else:
                print
                print2Log(logFile,"Service or Action found in file not valid... Skipping: " + act + "-" + serv)

4 - Now check these variables in the script:

varibles
1
2
3
4
dbFile="https://www.dropbox.com/s/XXXXXXXXXXXXXXXX/file"
logFile="/var/log/locker_log.log"
htmlFile="/usr/share/nginx/www/sshd.html"
servicesL={'ssh':'22','vpn':'1723','httpd':'80'}

Adapt the script to fit your environment:

  • Replace dbFile by the URL you got from Dropbox
  • Set the path you need for the logFile
  • The script will write the status of the services to my web server, so I can check the status easily. Set your path in htmlFile.
  • Define the list of services you want to manage in servicesL. This has to match with the info you define in the dropbox file.

5 - Create an entry in crontab with the periodicity you need. In my case, opening/closing ssh port is not critical, so, as I don’t want Dropbox people to get angry at me, I set it up to 5 minutes :)

crontad
1
 */5 * * * * python /path/to/portLocker.py &>> /var/log/locker_log.log

Now all you need to do is modify your dropbox file, and after a few minutes, check if you get the result you expected ;)

There is one main improvement that could be done, and it is adding some kind of signature to the file in order to ensure nobody is messing with us, but I have pretty good reasons not to do it (at the moment):

  • I update the dropbox file from mobile devices every now and then, and adding a signature to the file would make this way too complex.
  • This file is stored in my dropbox folder, so theoretically, nobody but me is able to modify it.
  • The security of the server does not rely on this script. This is not meant to be “security through obscurity”.

If you are after something more professional, I recommend you to check Latch.

And that’s all folks… It is working pretty well for me, and I hope it works for you…

See you around

New Look. Same Engine

| Comments

Dear reader, if you have ever been in a (long) business trip, you would problably agree with me on this:

“At the end, long business trips are pretty boring” (ok, ok, it depends on the place)

I have been in Amman (Jordan) for the past few weeks. I have seeing what could be seen around (not that much IMO), but since now I have some “spare” time, I have decided to take another look at Octopress. (I still think I would be better off without Ruby though :-P)

So, as you can see, I have modified the CSS of the site to make it cleaner and lighter, because I never really like dark styles.

Actually, this is how bynario.com looked like in 2005 (I found this in archive.org):

And this is in 2011 (I hosted this site in blogger for a few months):

And finally, since June 2012, I have been running Octopress with just some small modifications over the default theme:

Now I just need to stop procrastinating and post more often… Easier said than done!

Bye

Blog Engines Comparation

| Comments

I don’t like Ruby, at all… Maybe because I never really “used it” so didn’t have the opportunity to know its guts, or maybe because it just sucks… If you ask me, it is probably the latter :P

As you might know, Octopress (which is a great blog engine, kudos to Brandon Mathis) is written in Ruby, so every now and then I have to deal with rvm, and all the ruby paraphernaliam when an upgrade breaks it in my VM.

Working in an environment you are not familiar with is not easy and every time it breaks, I have to spend some time trouble-shooting it, so I have decided to take a look at other available blog engines, compare them with Octopress, and migrate to a more “friendly” environment (hopefully)

So I compared these three alternatives: Octopress, Tinkerer and Hugo

Python: Parsing XML Files

| Comments

I would like to continue with another small python example. As in the previous post,this is more like a “note to self” thing than a educational post (this is not stackoverflow), but anyway, I guess it could be handy for someone(it has been for me…)

This time, I have been testing two xml submodules availables in Python 2.7 XML package:

Both of them are pretty easy to use, and I haven’t found any real difference in time execution (at least for basic filters) between both submodules.

I will use this xml file as an example:

fakexml.xml
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
<?xml version="1.0"?>
<data>
  <node>
      <attribute>Front End</attribute>
      <res_ids>100</res_ids>
      <nEName>BALDR</nEName>
      <ipList>192.168.0.5</ipList>
      <ipv6List>fe80::1:f6f1:fe01:12</ipv6List>
      <so>Ubuntu</so>
      <kernel>3.0.93</kernel>
  </node>
  <node>
      <attribute>Web</attribute>
      <res_ids>12</res_ids>
      <nEName>THOR</nEName>
      <ipList>192.168.0.20</ipList>
      <ipv6List>fe80::1:f6f1:fe01:12</ipv6List>
      <so>Ubuntu</so>
      <kernel>3.0.93</kernel>
  </node>
  <node>
      <attribute>Storage</attribute>
      <res_ids>200</res_ids>
      <nEName>VALI</nEName>
      <ipList>192.168.0.10</ipList>
      <ipv6List>fe80::1:f6f1:fe01:12</ipv6List>
      <so>Ubuntu</so>
      <kernel>3.0.93</kernel>
  </node>
  <node>
      <attribute>DB</attribute>
      <res_ids>230</res_ids>
      <nEName>LOKI</nEName>
      <ipList>192.168.0.110</ipList>
      <ipv6List>fe80::1:f6f1:fe01:12</ipv6List>
      <so>Fedora</so>
      <kernel>3.0.93</kernel>
  </node>
  <node>
      <attribute>Backup</attribute>
      <res_ids>300</res_ids>
      <nEName>OTHER</nEName>
      <ipList>192.168.0.103</ipList>
      <ipv6List>fe80::1:f6f1:fe01:12</ipv6List>
      <so>Debian</so>
      <kernel>3.0.93</kernel>
  </node>
</data>

In the tree, we can see that we have one “data” object containing several “nodes”, each one with 7 “attributes”.

Now let’s extract the nodes and all the attributes using xml.dom:

print_table_from_xml_dom.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python
from xml.dom import minidom

def parse_file(filename):
    xmldoc = minidom.parse(filename)
    for node in xmldoc.getElementsByTagName('node'):
        print str(node.getElementsByTagName("attribute")[0].firstChild.nodeValue),
        print str(node.getElementsByTagName("res_ids")[0].firstChild.nodeValue),
        print str(node.getElementsByTagName("nEName")[0].firstChild.nodeValue),
        print str(node.getElementsByTagName("ipList")[0].firstChild.nodeValue)
        print str(node.getElementsByTagName("ipv6List")[0].firstChild.nodeValue)
        print str(node.getElementsByTagName("so")[0].firstChild.nodeValue)
        print str(node.getElementsByTagName("kernel")[0].firstChild.nodeValue)

parse_file("./fakexml.xml")

And now, the same thing using xml.etree.ElementTree:

print_table_from_xml_element.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python
from xml.etree import ElementTree as ET

def parse_file(filename):
    tree = ET.ElementTree(file=filename)
    attrList = [ entry for entry in tree.findall('./node') ]
    for e in attrList:
        print e.find('attribute').text,
        print e.find('res_ids').text,
        print e.find('nEName').text,
        print e.find('ipList').text,
        print e.find('ipv6List').text,
        print e.find('so').text,
        print e.find('kernel').text

parse_file("./fakexml.xml")

The output from any of the two options would be the same one:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$> python print_table_from_xml_dom.py
Front End 100 BALDR 192.168.0.5 fe80::1:f6f1:fe01:12 Ubuntu 3.0.93
Web 12 THOR 192.168.0.20 fe80::1:f6f1:fe01:12 Ubuntu 3.0.93
Storage 200 VALI 192.168.0.10 fe80::1:f6f1:fe01:12 Ubuntu 3.0.93
DB 230 LOKI 192.168.0.110 fe80::1:f6f1:fe01:12 Fedora 3.0.93
Backup 300 OTHER 192.168.0.103 fe80::1:f6f1:fe01:12 Debian 3.0.93


$> python print_table_from_xml_element.py
Front End 100 BALDR 192.168.0.5 fe80::1:f6f1:fe01:12 Ubuntu 3.0.93
Web 12 THOR 192.168.0.20 fe80::1:f6f1:fe01:12 Ubuntu 3.0.93
Storage 200 VALI 192.168.0.10 fe80::1:f6f1:fe01:12 Ubuntu 3.0.93
DB 230 LOKI 192.168.0.110 fe80::1:f6f1:fe01:12 Fedora 3.0.93
Backup 300 OTHER 192.168.0.103 fe80::1:f6f1:fe01:12 Debian 3.0.93

As I mentioned before, for this small exercise, there is no difference in terms of time of execution between both alternatives. I created a “slightly bigger” xml file (100x bigger), and the times were still pretty much the same, so I would say it is not a matter of the size, but the complexity of the filters.

To wrap up, let’s put this code together with the one in the previous post, where we created a table from the data in a dictionary.

I use ElementTree instead of xml.dom, but both of them would work. Here’s the code:

print_table_from_dict.py
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
#!/usr/bin/env python
import sys
from collections import defaultdict
from xml.etree import ElementTree as ET

if sys.argv[1:]:
    inputF = sys.argv[1]
else:
    print "ERROR. Execution failed: missing file"
    sys.exit(1)

total = defaultdict(list)

# Column width
AttrColLen=25
ValueColLen=20
colwidth1="{0:<"+str(AttrColLen)+"}"
colwidth2="{0:<"+str(ValueColLen)+"}"


# Printer function
def print_table(data):
    for key, values in sorted(total.items()):
        print "|" + AttrColLen*"-" + ((ValueColLen+2)*len(values))*"-" + "-|"
        print  "| " + colwidth1.format(key) + "|",
        for i in xrange(len(values)):
            print colwidth2.format(values[i])+"|",
        print ""
    print "|" + AttrColLen*"-" + ((ValueColLen+2)*len(values))*"-" + "-|"

# Parse the xml, and add the items to the dictionary
def parse_file(filename):
    colwidth1="{0:<30}"
    colwidth2="{0:<25}"

    tree = ET.ElementTree(file=filename)
    attrList = [ entry for entry in tree.findall('./node') ]
    for e in attrList:
        total["Attribute"].append(e.find('attribute').text)
        total["RES_ID"].append(e.find('res_ids').text)
        total["networkElementName"].append(e.find('nEName').text)
        total["IPv4"].append(e.find('ipList').text)
        total["IPv6"].append(e.find('ipv6List').text)
        total["SO"].append(e.find('so').text)
        total["Kernel"].append(e.find('kernel').text)


parse_file(inputF)
print_table(total)

And here is the result:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$> python print_table_from_dict.py fakexml.xml
|----------------------------------------------------------------------------------------------------------------------------------------|
| Attribute                | Front End           | Web                 | Storage             | DB                  | Backup              |
|----------------------------------------------------------------------------------------------------------------------------------------|
| IPv4                     | 192.168.0.5         | 192.168.0.20        | 192.168.0.10        | 192.168.0.110       | 192.168.0.103       |
|----------------------------------------------------------------------------------------------------------------------------------------|
| IPv6                     | fe80::1:f6f1:fe01:12| fe80::1:f6f1:fe01:12| fe80::1:f6f1:fe01:12| fe80::1:f6f1:fe01:12| fe80::1:f6f1:fe01:12|
|----------------------------------------------------------------------------------------------------------------------------------------|
| Kernel                   | 3.0.93              | 3.0.93              | 3.0.93              | 3.0.93              | 3.0.93              |
|----------------------------------------------------------------------------------------------------------------------------------------|
| RES_ID                   | 100                 | 12                  | 200                 | 230                 | 300                 |
|----------------------------------------------------------------------------------------------------------------------------------------|
| SO                       | Ubuntu              | Ubuntu              | Ubuntu              | Fedora              | Debian              |
|----------------------------------------------------------------------------------------------------------------------------------------|
| networkElementName       | BALDR               | THOR                | VALI                | LOKI                | OTHER               |
|----------------------------------------------------------------------------------------------------------------------------------------|

</bye!> ;)

Python: Print Table From Dictionary of Lists

| Comments

Hello

I have been trying to find an easy way to create ascii tables in Python using data from a dictonary of lists. I couldn’t find anything that suited me, so I came up with this small piece of code

1
2
3
4
5
6
7
8
def print_table(data):
    for key, values in sorted(total.items()):
        print "|" + AttrColLen*"-" + ((ValueColLen+2)*len(values))*"-" + "-|"
        print  "| " + colwidth1.format(key) + "|",
        for i in xrange(len(values)):
            print colwidth2.format(values[i])+"|",
        print ""
    print "|" + AttrColLen*"-" + ((ValueColLen+2)*len(values))*"-" + "-|"

It’s pretty simple, and does the job. Let me show it to you with an example

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
#!/usr/bin/env python
from collections import defaultdict

total = defaultdict(list)

# Column width
AttrColLen=25
ValueColLen=15
colwidth1="{0:<"+str(AttrColLen)+"}"
colwidth2="{0:<"+str(ValueColLen)+"}"

# Fake data 
attribute=['Front End','Web','Storage']
res_ids=['100','12','200']
nEName=['BALDR','THOR','VALI']
ipList=['192.168.0.5','192.168.0.20','192.168.0.10']

# Printer
def print_table(data):
    for key, values in sorted(total.items()):
        print "|" + AttrColLen*"-" + ((ValueColLen+2)*len(values))*"-" + "-|"
        print  "| " + colwidth1.format(key) + "|",
        for i in xrange(len(values)):
            print colwidth2.format(values[i])+"|",
        print ""
    print "|" + AttrColLen*"-" + ((ValueColLen+2)*len(values))*"-" + "-|"



# Populating the dictionary
for iter1 in attribute:
    total["Attribute"].append(iter1)
for iter2 in res_ids:
    total["RES_ID"].append(iter2)
for iter3 in nEName:
    total["networkElementName"].append(iter3)
for iter4 in ipList:
    total["IPv4"].append(iter4)  

# Let's print the dictionary
print total

Obviously there are other (better!!) ways to print a dictionary (like pprint),anyway I just wanted to show you how the dictionary looks like

1
2
3
4
defaultdict(<type 'list'>, {'Attribute': ['Front End', 'Web', 'Storage'],
'RES_ID': ['100', '12', '200'],
'networkElementName': ['BALDR', 'THOR', 'VALI'],
'IPv4': ['192.168.0.5', '192.168.0.20', '192.168.0.10']})

Now let’s replace:

1
2
# Let's print the dictionary
print total

By:

1
2
# Let's print the dictionary
print_table(total)

This is the result:

1
2
3
4
5
6
7
8
9
|-----------------------------------------------------------------------------|
| Attribute                | Front End      | Web            | Storage        |
|-----------------------------------------------------------------------------|
| IPv4                     | 192.168.0.5    | 192.168.0.20   | 192.168.0.10   |
|-----------------------------------------------------------------------------|
| RES_ID                   | 100            | 12             | 200            |
|-----------------------------------------------------------------------------|
| networkElementName       | BALDR          | THOR           | VALI           |
|-----------------------------------------------------------------------------|

It looks pretty nice, and the code is really simple…

I hope it helps

Byte!

Network Manager for Windows 7 Using cmd.exe

| Comments

Updated version of the script. Now it allows you to enable/disable the network interfaces

Hi there

Lately I have been changing the network properties (ip addresses, netmask, etc etc) in my laptop (W7 Enterprise 64b) several times per day, and to be honest I am growing tired of it, so I created a small bat script in order to make my life easier

The script is pretty simple… It might be handy for you as well, so here you are:

Network Managerlink
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
@ECHO OFF
SET OPTION=

goto :MENU

:MENU
cls
Echo #### CLI NETWORK MANAGEMENT ####
Echo.
Echo ****** LAN ******
Echo 1) LAN - DHCP
Echo 2) LAN - STATIC IP:192.168.2.10/24 - GW:192.168.2.99 - DNS:8.8.8.8
Echo 3) LAN - DEFINE NEW STATIC IP
Echo.
Echo ****** WIRELESS LAN ******
Echo 4) WLAN - DHCP
Echo 5) WLAN - STATIC IP:192.168.2.20/24 - GW:192.168.2.99 - DNS:8.8.8.8
Echo 6) WLAN - DEFINE NEW STATIC IP
Echo.
Echo ****** INTERFACES ******
Echo 7) SHOW INTERFACES STATUS
Echo 8) ENABLE LAN
Echo 9) DISABLE LAN
Echo 10) ENABLE WLAN
Echo 11) DISABLE WLAN
Echo.
Echo 0) Exit
Echo.
set /p OPTION=Option:
Echo.

IF "%OPTION%"=="0" call :END
IF "%OPTION%"=="1" call :Opt1 "Local Area Connection"
IF "%OPTION%"=="2" call :Opt2 "Local Area Connection" "192.168.2.10" "255.255.255.0" "192.168.2.99" "8.8.8.8"
IF "%OPTION%"=="3" call :Opt3 "Local Area Connection"
IF "%OPTION%"=="4" call :Opt1 "Wireless Network Connection"
IF "%OPTION%"=="5" call :Opt2 "Wireless Network Connection" "192.168.2.20" "255.255.255.0" "192.168.2.99" "8.8.8.8"
IF "%OPTION%"=="6" call :Opt3 "Wireless Network Connection"
IF "%OPTION%"=="7" call :Opt4
IF "%OPTION%"=="8" call :Opt41 "Local Area Connection" "ENABLED"
IF "%OPTION%"=="9" call :Opt41 "Local Area Connection" "DISABLED"
IF "%OPTION%"=="10" call :Opt41 "Wireless Network Connection" "ENABLED"
IF "%OPTION%"=="11" call :Opt41 "Wireless Network Connection" "DISABLED"


goto :MENU

:Opt1
REM DHCP
REM "%~1" - Interface Name
cls
Echo Configuring %~1 as DHCP...
Echo.
Echo Configuring DHCP for IP
netsh interface ip set address "%~1" dhcp
Echo Configuring DHCP for dns
netsh interface ip set dns "%~1" dhcp
Echo Configuring DHCP for wins
netsh int ip set wins name="%~1" dhcp
Echo.
Echo Checking configuration
netsh interface ip show config name="%~1"
Echo.
pause
goto :MENU


:Opt2
REM STATIC IP
REM "%~1" - Interface Name
REM "%~2" - IP
REM "%~3" - NETMASK
REM "%~4" - GW
REM "%~5" - DNS
cls
Echo Configuring static IP address for %~1
Echo =============================================
Echo.
Echo Configuring IP %~2 %~3 %~4
netsh interface ip set address name="%~1" static "%~2" "%~3" "%~4"
Echo Configuring DNS %~5
netsh interface ip set dns name="%~1" static "%~5"
netsh interface ip add dns name="%~1" 8.8.4.4
Echo.
Echo Checking configuration
netsh interface ip show config name="%~1"
pause
goto :MENU

:Opt3
REM STATIC IP - NEW
REM "%~1" - Interface Name
cls
set /p IP=IP:
set /p NET=NETMASK:
set /p GW=GATEWAY:
set /p DNS=DNS:
Echo Configuring new static IP address for %~1
Echo =============================================
Echo.
Echo Configuring IP %IP% %NET% %GW%
netsh interface ip set address name="%~1" static "%IP%" "%NET%" "%GW%"
Echo Configuring DNS %DNS%
netsh interface ip set dns name="%~1" static "%DNS%"
Echo Configuring secondary DNS 8.8.4.4
netsh interface ip add dns name="%~1" 8.8.4.4
Echo.
Echo Checking configuration
netsh interface ip show config name="%~1"
pause
goto :MENU

:Opt4
REM INTERFACES
REM "%~1" - Interface Name
REM "%~2" - status
cls
Echo ****** INTERFACES ******
Echo.
Echo Checking network interface status...
Echo.
netsh interface  show interface | find /i "connection"
Echo.
pause
goto :MENU

:Opt41
cls
Echo ****** INTERFACES ******
Echo.
Echo Setting %~1 status to ... %~2
netsh interface set interface name="%~1" admin="%~2"
goto :Opt4


:END
exit

The script needs to be executed as administrator…

Online Again

| Comments

It’s been a while…. but better late than never, isn’t it? I am back online (I never left, but this site didn’t come back after a VPS migration)…

Not a single post in 2013… “Working, working and working” that would sum up the whole last year.

These are my thoughts about a few things that happened in 2013:

  • RaspberryPi:

I got mine (pre-ordered) in the fall of 2011… Well actually I paid it then, but it was delivered in Jun 2012. In 2013 I bought another one to use it as a media center with raspbmc. What a piece of HW for only 37 euros.

  • Python:

I know I know, Python is OLD, but believe or not, I never used it before until 2013. I am not a developer, but Bash and Perl gave me pretty much everything I needed… Until I started to play with Python, it’s easy, fast, and there are modules for almost everything you can think of.

  • Ansible:

According to them, “a radically simple IT orchestration solution”, and you bet it is. Give it a chance if you can. Way easier than Puppet/Chef/Fabric…

  • G+:

I think the number of users in Google+ is ramping up mainly because it’s mandatory if you want to use some Google products. Unfortunatelly, it didn’t reach my expecations. There are some interesing stuff, but I am kind of bored of seeing animated gifs.

  • New family member:

After a few years using “old” computers (and my company laptop), I decided to buy a Lenovo x230, together with a 256GB Samsung SSD 840 PRO. To put is simple, it is F.A.S.T. As usually, GNU/Debian is the OS of choice. Still, some days I have second thoughs about it. Should I have bought a MBA 11” or this one?? I haven’t reach any conclusion yet :)

  • Bye bye Google Reader

At the end, it wasn’t a big deal. I had been a G.Reader power user for years, but due to my limited time, I started to check my feeds in the tablet (Nexus 7 2012) instead than in the laptop, and moving to Feedly was a smooth migration. You know what they say… the king is dead, long live the king.

  • Iceland and again to the US:

I did spent the whole year working long hours and weekends, but at least, I could take a few days off (in two different periods) and visited Iceland and some cities in the US East Coast. Iceland is amazing, it is like Jurasic Park (geologically speaking). You should totally go.

And again, back to the US… We had a really good time, as usual.

I will try to write a few post this year, but I can’t promise anything

//Bye

Monitoring Remote Systems: Using GTalk Notifications

| Comments

Since a few weeks ago I am using a Raspberry Pi as bittorrent client instead of my old, big and noisy Pentium III 1Ghz

I am pretty happy with the change (besides a few issues with the USB/Network controller). I managed to get rid of a big PC case, there are no fans spinning anymore (noiseless), and the power consumption is unbeatable, and I only paid around $40. Win-Win situation, isn’t it?.

But this post is not about my rasPi (ok, maybe just a little bit), but about how to received XMMP notification from a remote system. In this case, I was interested in sending a brief report of my VPS status (CPU,MEM,HD, etc) every 12 hours to my Gtalk account, so I can see how it is doing.

Most of the alternatives are based on sending emails, but I wasn’t very keen on setting up a MTA only to send a few reports every X hours, so I decided to use XMMP notifications instead.

Googling a little bit I found this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apt-cache show sendxmpp
Package: sendxmpp
Priority: optional
Section: net
Installed-Size: 88
Maintainer: Guus Sliepen <guus@debian.org>
Architecture: all
Version: 1.20-1
Depends: perl, libnet-xmpp-perl
Filename: pool/main/s/sendxmpp/sendxmpp_1.20-1_all.deb
Size: 15026
MD5sum: 2a3fcdc995442ebd1f7d8a336fc88164
SHA1: 90dd5cc21c9b97872dec5a55ce9d55ea7d728d65
SHA256: eb8a2fd09ffc65c04cc54a8a718faf550b5864a3135a9d045d2657cd43ed0449
Description: commandline XMPP (jabber) utility
 sendxmpp is a perl script to send XMPP (jabber) messages, similar to what
 mail(1) does for mail. XMPP is an open, non-proprietary protocol for instant
 messaging. See www.jabber.org for more information.
Tag: implemented-in::perl, interface::commandline, protocol::jabber, role::program, scope::utility

Just what I needed.

PROs: - Easy to use and integrate in simple scripts. - Perl script available in Debian repositories. - Lightweight. There are no daemons running. The script is executed whenever is needed. - Secure. Using SSL.

CONS: - Only available to GTalk users (obviously). - Limited size of the message. (just because of the limited size of the screen of your mobile device) - In order to avoid SPAM, the account where you are sending the message from, has to be in the contact list of the receiver.

As, it was working like a charm in my Raspberry Pi, I decided to do the same in my VPS. Let me describe in a few steps how to configure it:

Installation? Debian’s way.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apt-get install sendxmpp
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
  libauthen-sasl-perl libdigest-sha1-perl libio-socket-ssl-perl libnet-libidn-perl libnet-ssleay-perl libnet-xmpp-perl
  libxml-stream-perl
Suggested packages:
  libdigest-hmac-perl libgssapi-perl libio-socket-inet6-perl libnet-dns-perl
The following NEW packages will be installed:
  libauthen-sasl-perl libdigest-sha1-perl libio-socket-ssl-perl libnet-libidn-perl libnet-ssleay-perl libnet-xmpp-perl
  libxml-stream-perl sendxmpp
0 upgraded, 8 newly installed, 0 to remove and 0 not upgraded.
Need to get 581 kB of archives.
After this operation, 2,543 kB of additional disk space will be used.
Do you want to continue [Y/n]? Y

Pretty easy configuration. Under your home directory, create a .sendxmpprc file

1
2
# cat .sendxmpprc
<your_email>@gmail.com <your_password>

Let’s test it. First sending a message from the standard input:

1
echo "hello there" | /usr/bin/sendxmpp  -t -u <your_email> -o gmail.com <recipient Google ID>

Notification received:

And now, sending the text from a file:

1
2
echo "this is a message send from a text file" > text.txt
/usr/bin/sendxmpp -t -u <your_email> -o gmail.com <recipient Google ID> -m text.txt

Notification received:

Working!

Integrating it in a simple bash script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash

REPORT="/tmp/.report"

[  -f $REPORT ] && rm -f $REPORT
echo  "VPS report at `date`:" >> $REPORT
echo  "Machine stats : `uptime`" >> $REPORT
echo  "Memory stats : `free -m`" >> $REPORT
echo  "Hard Disk Space: `df -h`" >> $REPORT
echo "" >> $REPORT


#Sending the report to GTALK
/usr/bin/sendxmpp -t -u <your_email> -o gmail.com <recipient Google ID> -m $REPORT

And setting up the task in cron:

1
2
crontab -e
57 17 * * * sh /scripts/send_report.sh

The notification received in my Gtalk client:

This is just an example, but I am pretty sure you could find a lot of applications to this basic notification system

Enjoy!

Cacti Monitoring Over SSH

| Comments

Recently I had to configure Cacti in order to monitor several blades in a cluster (nothing fancy, just CPU load, memory usage, load average and disk space) but this time NET-SNMP wasn’t an option. I knew that I could use server scripts to access the remote blades using SSH, so after googling a while, I found this proejct from the Percona guys:

Percona Monitoring Plugins for Cacti

What can I say… Amazing. Everything working in a few minutes.

Although all the information about Cacti and Percona plugins can be found in their web sites, I decided to put it all together and take a few screenshots, so if you happen to do something similar, this is what I did:

Let’s assume that you have a fresh a Debian box (In my case, I created a Debian virtual machine, running testing for this)

1) Install cacti (and its dependences) using aptitude

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
aptitude install cacti
The following NEW packages will be installed:
  apache2-mpm-prefork{a} apache2-utils{a} apache2.2-bin{a}
  apache2.2-common{a} cacti dbconfig-common{a} libaio1{a}
  libapache2-mod-php5{a} libaprutil1-ldap{a} libcairo2{a} libdatrie1{a}
  libdbd-mysql-perl{a} libdbi-perl{a} libdbi0{a} libfontenc1{a}
  libhtml-template-perl{a} libmysqlclient16{a} libnet-daemon-perl{a}
  libonig2{a} libpango1.0-0{a} libpango1.0-common{a} libphp-adodb{a}
  libpixman-1-0{a} libplrpc-perl{a} libpng12-0{a} libqdbm14{a} librrd4{a}
  libthai-data{a} libthai0{a} libx11-6{a} libx11-data{a} libxau6{a}
  libxcb-render-util0{a} libxcb-render0{a} libxcb1{a} libxdmcp6{a}
  libxfont1{a} libxft2{a} libxrender1{a} mysql-client-5.1{a}
  mysql-client-5.5{ab} mysql-common{a} mysql-server{a} mysql-server-5.5{ab}
  mysql-server-core-5.5{ab} php5-cli{a} php5-common{a} php5-mysql{a}
  php5-snmp{a} php5-suhosin{a} rrdtool{a} x-ttcidfont-conf{a} x11-common{a}
  xfonts-encodings{a} xfonts-utils{a}

2) Setup your timezone in php.ini

There are three different “php.ini” files in Debian:

1
2
3
/etc/php5/cli/php.ini
/etc/php5/apache2/php.ini
/etc/php.ini

Cacti is using PHP over the CLI, so it should be enough if you update “/etc/php5/cli/php.ini”, but I would update all of them. Add this line to the file:

1
date.timezone = "<time zone>"

For example:

1
date.timezone = "Asia/Tokyo"

The list of timezones is available here

3) Apache+MySQL+PHP+Cacti working out of the box with just a few commands

At this point you should be able to login in cacti on your apache webserver (http://VM_IP/cacti)

The default user/password is admin/admin. (the system will ask you to change it after the first login)

I won’t explain Cacti configuration, because they already have very good documentation in their web site

4) Setting up the SSH authentication

This chapter is pretty well explained in Percona web site.

Basically we have to:
- Set up an SSH keypair for SSH authentication.
- Create a user on the remote server you want to graph.
- Install the public key into that user.s authorized_keys file.

Check the detailed information here Percona: SSH-Based Templates

5) Installing “Percona Monitoring Plugins for Cacti”

Download the plugins from Percona website: Percona - Download percona-monitoring-plugins

1
wget http://www.percona.com/redir/downloads/percona-monitoring-plugins/percona-monitoring-plugins-1.0.1.tar.gz

Extract the file, and copy ss_get_by_ssh.php to Cacti script folder:

1
2
tar zxvf percona-monitoring-plugins-1.0.1.tar.gz
cp percona-monitoring-plugins-1.0.1/cacti/scripts/ss_get_by_ssh.php /usr/share/cacti/site/scripts/

Edit /usr/share/cacti/site/scripts/ss_get_by_ssh.php with your remote user name and the path to the SSH identity from step 4.

1
2
$ssh_user   = 'cacti';                          # SSH username
$ssh_iden   = '-i /var/www/cacti/.ssh/id_rsa';  # SSH identity

6) Importing the template

Inside the tar file you will find different templates:

1
2
3
4
5
6
7
8
9
10
11
/percona-monitoring-plugins-1.0.1/cacti/templates# ls -lrt
total 1644
-rw-r--r-- 1 501 root 169078 Jun 15 04:44 cacti_host_template_percona_openvz_server_ht_0.8.6i-sver1.0.1.xml
-rw-r--r-- 1 501 root  41926 Jun 15 04:44 cacti_host_template_percona_nginx_server_ht_0.8.6i-sver1.0.1.xml
-rw-r--r-- 1 501 root 843345 Jun 15 04:44 cacti_host_template_percona_mysql_server_ht_0.8.6i-sver1.0.1.xml
-rw-r--r-- 1 501 root  89553 Jun 15 04:44 cacti_host_template_percona_mongodb_server_ht_0.8.6i-sver1.0.1.xml
-rw-r--r-- 1 501 root  75491 Jun 15 04:44 cacti_host_template_percona_memcached_server_ht_0.8.6i-sver1.0.1.xml
-rw-r--r-- 1 501 root  53416 Jun 15 04:44 cacti_host_template_percona_jmx_server_ht_0.8.6i-sver1.0.1.xml
-rw-r--r-- 1 501 root 249175 Jun 15 04:44 cacti_host_template_percona_gnu_linux_server_ht_0.8.6i-sver1.0.1.xml
-rw-r--r-- 1 501 root  73879 Jun 15 04:44 cacti_host_template_percona_apache_server_ht_0.8.6i-sver1.0.1.xml
-rw-r--r-- 1 501 root  37198 Jun 15 04:44 cacti_host_template_percona_redis_server_ht_0.8.6i-sver1.0.1.xml

In our case, we are only interested in cacti_host_template_percona_gnu_linux_server_ht_0.8.6i-sver1.0.1.xml

Console -> Import Templates -> Import template:

7) Create a new device

Under Console -> Devices, add a new device:

And complete the information (name, IP)

8) Modify the data template and the data source (I will use “Percona Disk Space DT” as example)

Check the Percona Data Templates availables:

Console -> Data Templates

Click in the name (Percona Disk Space DT) and let’s edit the template. Go to the bottom of the page, and check “Custom Data”:

Add Percona Disk Space DT as new data source for your host. Under Console -> Data Sources, click new:

Set the Remote IP and the partition (or volumen) to monitor

9) Create the graph

We have already created the data source for our remote server, so now, we just have to create a new graph.

Under Console -> Graph Management, add a new graph:

And select our data source (Percona Disk Space DT) for the device:

10) Result

At this point, the graph should be created, and after a few minutes, you should see something like this:

If something goes wrong, take a look at /var/log/cacti/cacti.log. There should be a line similar to this one:

1
<DATE> - CMDPHP: Poller[0] Host[3] DS[25] CMD: /usr/bin/php -q /usr/share/cacti/site/scripts/ss_get_by_ssh.php --host <REMOTE_IP> --type proc_stat --items gg,gh,gi,gj,gk,gl,gm,gn,go, output: gg:50994 gh:0 gi:76580 gj:56353167 gk:1617 gl:0 gm:0 gn:2135 go:-1