Skip to main content

In memory of Ray Dassen (JHM)

It's unfortunately very official now, our beloved Red Hat colleague and friend Ray Dassen has passed away. I still can't believe it, as we had just spent a week in Brno together less than a month ago. I will always remember him. JHM++

Here is a little a little gem we (*) came up with some weeks ago while debugging some strace outputs.

Given a strace line like the following:

recvfrom(5, "r\33\205\200\0\1\0\1\0\0\0\0\tboxen1222\4corp\6foobar\3com\0\0\1\0\1\300\f\0\1\0\
1\0\0\16\20\0\4\n\351\360\26", 1024, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("
10.10.1.1")}, [16]) = 59

You can feed it to tshark with the following:

printf "\336\316\205\200\0\1\0\1\0\0\0\0\tboxen1222\4corp\6foobar\3com\0\0\1\0\1\300\f\0\1\0\1\0\0\16\20\0\4\n\351\360\26" | \
 od -Ax -tx1 -v  | text2pcap -d -u 53,6666 - /tmp/tmp.pcap && tshark -x -V -r /tmp/tmp.pcap

(*) By "we" I really mean Ray

Telecom Italia ADSL and IPv6

Surprisingly enough (to me at least), I discovered that my ISP actually does support IPv6. You simply need to configure your PPP connection with the following:

  • Username: adsl@alice6.it
  • Password: IPV6@alice6

On my Debian-based Soekris firewall I use shorewall to manage the filtering rules. Eth4 is the internal ADSL modem and eth0 is the internal network. In order to distribute IPv6 to my home network I added the following to /etc/ppp/ipv6-up.d/dsl-provider (nb: it needs the ndisc6 package) :

 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
#!/bin/bash
# Get the /64 network we've been assigned
prefix=$(rdisc6 -1 -q ppp0)
# External interface gets $prefix::1
ip1=$(echo $prefix | sed 's/::\/64/::1\/128/')
ip -6 addr add ${ip1} dev ppp0
# Internal eth0 interface gets $prefix:ffff:ffff:ffff:fffe
ip2=$(echo $prefix | sed 's/::\/64/:ffff:ffff:ffff:fffe\/64/')
ip -6 addr flush scope global dev eth0
ip -6 addr add ${ip2} dev eth0

ip -6 r a default dev ppp0

# Customize and then restart radvd
cat > /etc/radvd.conf <<EOF
interface eth0 {
        AdvSendAdvert on;
        prefix $ip2 {
                AdvOnLink on;
                AdvAutonomous on;
                AdvRouterAddr on;
        };
};
EOF

/etc/init.d/radvd restart

Building your own FC SAN with Linux

silkworm

With the Linux kernel 3.5 release the Fibre Channel SCSI Target support has been merged. This means that given a couple of QLogic cards and a Fibre Channel SAN switch you can actually build your own cheap FC SAN environment. I thought of giving it a shot and hit eBay to get:

  • Brocade Silkworm 3250 with 4 SFPs
  • 2 x QLogic ISP2432 HBAs
  • Fibre Optic cables

The small challenge was to actually reset the configuration of the Brocade switch as I kept receiving no output from the serial console. A quick google showed that the DB-9 serial cable needs to have pins 2,3 and 5 connected straight between the connectors. After a little soldering I finally got proper serial output and managed to reset it. Following this excellent guide I reset the password in no time.

Here is the info regarding my setup:

  • marquez - Fedora 19 (as of 20th of May). The target system containing the LUN. Its qla2xxx has WWN: 0x210000e08b943494
  • h2 - RHEL 6.4. The "client" system. WWN: 0x210000e08b947193
  • FC Switch - Fabric OS 4.2.2. WWN: __ 10:00:00:05:1e:35:d9:0a

FC Switch

Let's start to configure the FC Switch. We'll create a simple ZONE adding the WWN's of the involved parties.

> cfgClear
> aliCreate HBA_MARQUEZ, 21:00:00:e0:8b:94:71:93
> aliCreate HBA_H1, 21:00:00:e0:8b:94:34:94
> zoneCreate "SAN", "HBA_MARQUEZ; HBA_H1"
> cfgDisable
 Updating flash ...
> cfgshow
 Defined configuration:
 zone: SAN HBA_MARQUEZ; HBA_H1
 alias: HBA_H1 21:00:00:e0:8b:94:34:94
 alias: HBA_MARQUEZ 21:00:00:e0:8b:94:71:93

Effective configuration:
 no configuration in effect

> cfgcreate SAN_CFG, "SAN" 
> cfgenable SAN_CFG
 zone config "SAN_CFG" is in effect
Updating flash ...

With the above we created a single zone called 'SAN'. The two HBAs are members of this zone.

Target

We need to disable the initiator mode from the qla2xxx driver:

# echo 'options qla2xxx qlini_mode="disabled"' > /usr/lib/modprobe.d/qla2xxx.conf
# rmmod qla2xxx
# modprobe qla2xxx

(Note that it's better to put it under /usr/lib... as most likely qla2xxx will be loaded from your initramfs. Don't forget to rebuild the initram with 'dracut -f'. Then we install targetcli and start configuring the LUN and the ACLs on the LUN:

# yum install -y targetcli
# targetcli
/> qla2xxx/ info
Fabric module name: qla2xxx
ConfigFS path: /sys/kernel/config/target/qla2xxx
Allowed WWN types: naa
Allowed WWNs list: naa.210000e08b943494
Fabric module features: acls
Corresponding kernel module: tcm_qla2xxx

/> /qla2xxx create naa.210000e08b943494
Created target naa.210000e08b943494.
/> /backstores/block create lun1 /dev/sdb
Created block storage object lun1 using /dev/sdb.
/> /qla2xxx/naa.210000e08b943494/luns create /backstores/block/lun1
Created LUN 0.
/> /qla2xxx/naa.210000e08b943494/acls create 210000e08b947193

Note that if there are any errors in the FC Switch configuration we will see errors like 'SNS scan failed -- assuming zero-entry result.' in your messages.

Initiator

We can just issue a LIP or rescan the scsi device and we will see the LUN:

# echo 1 > /sys/class/fc_host/host9/issue_lip

# tail -f /var/log/messages
May 20 22:49:24 h2 kernel: qla2xxx [0000:40:00.0]-505f:9: Link is operational (2 Gbps).
May 20 22:49:27 h2 kernel: scsi 9:0:0:0: Direct-Access     LIO-ORG  lun1             4.0  PQ: 0 ANSI: 5
May 20 22:49:27 h2 kernel: sd 9:0:0:0: Attached scsi generic sg2 type 0
May 20 22:49:27 h2 kernel: sd 9:0:0:0: [sdb] 293046768 512-byte logical blocks: (150 GB/139 GiB)
May 20 22:49:27 h2 kernel: sd 9:0:0:0: [sdb] Write Protect is off
May 20 22:49:27 h2 kernel: sd 9:0:0:0: [sdb] Write cache: enabled, read cache: enabled, supports DPO and FUA
May 20 22:49:27 h2 kernel: sdb: sdb1
May 20 22:49:27 h2 kernel: sd 9:0:0:0: [sdb] Attached SCSI disk

At this point we can use /dev/sdb as a normal block device.

List all your Forwarders with Powershell

I clearly lied about on my previous post about being the last Microsoft-based post. Here's what I did to check all our forwarders in our forest:

$domain = "corp.local"
$myForest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$dc_list = $myforest.Sites | % { $_.Servers } | Select Name

foreach ($dc in $dc_list) {
    $DCName = $dc.Name
    $Server = Get-WMIObject -Computer $DCName -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_Server"
    $Forwarders = $Server.Forwarders
    Write-Host $DCName ":" $Forwarders
}

Lync Contact Groups and Powershell

This will be likely one of my last Windows posts (more on that later). At work we did upgrade our OCS Server to Lync. Besides the annoyance of changing product name every two releases, this new version removed the possibility that existed in OCS to provision the contact groups for the ocs client. It was a WMI interface and it was quite handy.

Especially in cases where the rollout is not company-wide and users aren't sure who has Lync and who doesn't, having groups provisioned administratively is very handy. So I spent a couple of evenings solving this topic and it turned out that it's not really that difficult ;)

After poking a bit in the DB I noticed some handy stored procedures that would be quite handy. So I cooked up a script that takes a folder and for every csv file stored in that folder (one samaccount per line), it creates a group named as the file and it populates it with the users contained in that file. I.e.: the file IT-Dept.csv that contains users jon123 and joe456, will create a group called "IT-Dept" which contains both users and only for those two users.

Disclaimer: this script is still buggy, it's coded horrendously and it's a very quick hack. Backup your db before toying with it. I won't have time to clean it up or refine it so feel free to tweak it, put it on github etc ;)

Here it is: sync-lync-rosters.ps1

Microsoft PKI and Powershell

I need to check among all issued certificates from a Microsoft PKI if there is a disabled or non valid Active Directory account. Since powershell seems to be the future for scripting on Microsoft platform, I cooked up the following script: check-ad-pki.ps1 It uses the powershell PKI module which can be found here.

It's my first stab at something with powershell, so I do appreciate any feedback on this. If anyone has better approaches to check the issue of certificates for a user that is now disabled or expired, that would be cool too ;)

Nagios Check for Fortigate Clusters

It's the month of nagios checks I guess.. I needed to monitor the status of the HA Fortigate clusters we have around the world. There is a very rudimentary plugin on the nagios exchange site, but it is a perl script that forks another perl script a bunch of times and I already have 600 hosts and more than a thousand services, so I thought I'd implement something a bit cleaner in python ;)

The only documentation on the Fortigate HA Mibs I was able to find is here: http://www.oidview.com/mibs/12356/FORTINET-MIB-280.html

Interestingly enough the OID that contains the names of the nodes in the cluster (SNMPv2-SMI::enterprises.12356.1.100.6.1.11.) is nowhere mentioned there. The standard Fortigate cluster is a fairly strange beast in the sense that there is only one ip address (no physical ip's plus the virtual one like in most clusters) and the firewalls exchange all the configuration and info through multicast on a separate link. That's why the first time the script runs it stores the names and the serial numbers of the nodes in a file and then checks that the order is the same in its subsequent runs.

Here is the script: fortinet-ha.py

I didn't add any snmp v1 or snmp v3 support as I have no time at the moment, but that should be quite trivial to add.

dd & mount

Long time no blog. As a note to myself, so I won't forget anymore:

When you pull a full disk image (sda.disk) with dd and it contains more than one partition just do the following (multiply times 512 bytes the sector start, mount will figure the rest out by itself):

bazz:/mnt/ntfs/# sfdisk -l -uS sda.disk 
Disk sda.disk: cannot get geometry

Disk sda.disk: 9729 cylinders, 255 heads, 63 sectors/track
Units = sectors of 512 bytes, counting from 0

 Device Boot    Start       End   #sectors  Id  System
sda.disk1            63 156296384  156296322   7  HPFS/NTFS
sda.disk2   *  19438650  19470779      32130   e  W95 FAT16 (LBA)
 start: (c,h,s) expected (1023,254,63) found (1023,0,1)
sda.disk3             0         -          0   0  Empty
sda.disk4             0         -          0   0  Empty
bazz:/mnt/ntfs/# mount -oloop,offset=$(echo "63*512" | bc) sda.disk /mnt/foo

Mediawiki and greensql

If you want to use the green sql firewall with mediawiki, you'll need a small patch that disables the SQL comments in every query:

diff -up ./includes/db/Database.php.orig ./includes/db/Database.php
--- ./includes/db/Database.php.orig    2011-01-15 20:31:07.000000000 +0100
+++ ./includes/db/Database.php    2011-01-15 20:31:48.000000000 +0100
@@ -473,19 +473,19 @@ abstract class DatabaseBase {

 # Add a comment for easy SHOW PROCESSLIST interpretation
 #if ( $fname ) {
-            global $wgUser;
-            if ( is_object( $wgUser ) && !($wgUser instanceof StubObject) ) {
-                $userName = $wgUser->getName();
-                if ( mb_strlen( $userName ) > 15 ) {
-                    $userName = mb_substr( $userName, 0, 15 ) . '...';
-                }
-                $userName = str_replace( '/', '', $userName );
-            } else {
-                $userName = '';
-            }
-            $commentedSql = preg_replace('/\s/', " /* $fname $userName */ ", $sql, 1);
+        #    global $wgUser;
+        #    if ( is_object( $wgUser ) && !($wgUser instanceof StubObject) ) {
+        #        $userName = $wgUser->getName();
+        #        if ( mb_strlen( $userName ) > 15 ) {
+        #            $userName = mb_substr( $userName, 0, 15 ) . '...';
+        #        }
+        #        $userName = str_replace( '/', '', $userName );
+        #    } else {
+        #        $userName = '';
+        #    }
+    #    #    $commentedSql = preg_replace('/\s/', " /* $fname $userName */ ", $sql, 1);
 #} else {
-        #    $commentedSql = $sql;
+            $commentedSql = $sql;
 #}

 # If DBO_TRX is set, start a transaction