Sunday, March 16, 2014

hosting http and https domains with lighttpd

I have two domains, one with an SSL certificate and one without. I wanted to host these on the same lighttpd server which only has one IP address.

There are several forum threads and lighty wiki articles about this, but none really cover a concise example of how to do it. Many parts of the documentation are confusing and non-obvious, the situation is not helped by the fact that you cannot do name-based SSL hosting, so what you'd expect to be the logical configuration doesn't work.

After staring at these for a few hours:
And a lot of trial-and-error, here's the config I ended up using:

$HTTP["scheme"] == "http" {

  $HTTP["host"] =~ "(^|\.)without.com" {
    server.name = "without.com"
    server.document-root = "/var/www/without.com"
  }

  else $HTTP["host"] =~ "(^|\.)withssl.com" {
    url.redirect = (".*" => "https://www.withssl.com$0")
  }

}
 

$HTTP["scheme"] == "https" {

  $SERVER["socket"] == "X.X.X.X:443" {

    server.name = "withssl.com"
    ssl.engine  = "enable"
    ssl.ca-file = "/etc/lighttpd/certs/ca-cert-class1.crt"
    ssl.pemfile = "/etc/lighttpd/certs/withssl.com.crt"

    server.document-root = "/var/www/withssl.com"

    # mitigate BEAST attack
    ssl.cipher-list = "ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4-SHA:RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM"
    # mitigate CVE-2009-3555
    ssl.disable-client-renegotiation = "enable"
  }
}


The "X.X.X.X" needs to be your server's IP address, the same IP which the domain in your SSL cert resolves to.

I haven't tested, but you could probably scale this up to host multiple non-SSL domains on the same host as the SSL domain. Hosting multiple SSL domains is well-covered in the lighty documentation.

The SSL cert and setup I did by following Switch to HTTPS Now, For Free over at Eric Mill's blog.

When using lighttpd, you'll also need these instructions to make a unified certificate.

Tuesday, February 4, 2014

realtek RTL8188CUS slow on Raspberry Pi

I recently had an adventure troubleshooting slow wifi on one of my Raspberry Pi systems. No matter what I did, I could not get more than 57 kilobytes per second transfer speed to it.

First I tried different transfer methods (Samba and SSH) with no change, so it wasn't the transfer method.

Then I tested the storage. I changed to a fast USB hard drive, moved the USB hard drive around the USB hub in case of power/throughput issues, but was eventually satisfied it wasn't storage when I could get 22 megabyte throughput with a hdparm -t. I should have just done that first.

Next I suspected either USB or wifi.

A lot of forum posts suggest to try dwc_otg.speed=1 in cmdline.txt however that reduces the chipset to USB1 speeds (11Mb/sec) which wasn't a compromise I was willing to make. There was mention of something called FIQ from 2011/2012, but these improvements are included in the latest (2014-01-07) Raspbian image, so there's no need to tinker with FIQ anymore.

I wondered if it was the wifi signal, so I moved the Pi right next to the router, but no change. I plugged in an ethernet cable and the speed improved immensely. So it was either USB or wifi.

Searching around, I read many reports of people having problem with these Realtek RTL8188CUS (driver 8192cu) wifi dongles. There were several suggestions to make a file like /etc/modprobe.d/8192cu.conf and turn off the adaptor's power management features with the contents:

options 8192cu rtw_power_mgnt=0 rtw_enusbss=0

I tried this but still no luck, transfers still sat at 57kb/sec.

At this point I remembered my other Raspberry Pi was using a different USB wifi adaptor, an RaLink RT5370 (driver rt2800usb). I tried this dongle and the speed instantly improved. We can now rule out USB and wifi signal, and place the blame on the wifi adaptor.

I have two of these Realtek adaptors, a black one with EDUP on it, and a white one with COMFAST on it. Both produced the slow transfer speed, so it wasn't unique to this one adaptor.

As best I can figure out, either Realtek's driver or the implementation of the wifi hardware is rubbish, and there's no way it can be fixed.

I've ordered another RaLink dongle off eBay.

Thursday, November 21, 2013

yum grouplist doesn't display all groups

I've noticed in Fedora that the yum grouplist command doesn't actually display all the groups:

# yum grouplist | grep Virt
# yum grouplist | grep Virt | wc -l 0

However you can still see a group with groupinfo:

# yum groupinfo Virtualization
Loaded plugins: langpacks, list-data, presto, refresh-packagekit
Group: Virtualization
 Group-Id: virtualization
 Description: These packages provide a virtualization environment.


Apparently there can be a "hidden" tag on groups, as reported in this Bugzilla entry:

Bug 986531 - unhide all groups from yum grouplist

You can see all the groups with the yum grouplist hidden command:

# yum grouplist | wc -l
39
# yum grouplist hidden | wc -l
126

Wednesday, November 13, 2013

how does mke2fs decide automatic check mount count?

Whenever you create an ext3 or ext4 filesystem with mkfs or mke2fs, a message is printed saying "This filesystem will be automatically checked every X mounts or Y days, whichever comes first".

However, the number seems to vary depending on the filesystem. How is this value calculated? I used the source of e2fsprogs-1.42.8 and the cscope source code tool to find this out.

Searching for the origin of the message, we can search for a short part of the string like "mounts or", and we see it's printed by this function:

"misc/util.c"
    281 void print_check_message(int mnt, unsigned int check)
    282 {
    283     if (mnt < 0)
    284         mnt = 0;
    285     if (!mnt && !check)
    286         return;
    287     printf(_("This filesystem will be automatically "
    288          "checked every %d mounts or\n"
    289          "%g days, whichever comes first.  "
    290          "Use tune2fs -c or -i to override.\n"),
    291            mnt, ((double) check) / (3600 * 24));
    292 }


Which is called here:

"misc/tune2fs.c"
    628 /*
    629  * Add a journal to the filesystem.
    630  */
    631 static int add_journal(ext2_filsys fs)
    632 {
    ...
    696     print_check_message(fs->super->s_max_mnt_count,
    697                 fs->super->s_checkinterval);


So now we need to find what puts the value into s_max_mnt_count. Hunting for uses of that symbol, we see an equals sign here:

"misc/mke2fs.c"
   2440     if (get_bool_from_profile(fs_types, "enable_periodic_fsck", 0)) {
   2441         fs->super->s_checkinterval = EXT2_DFL_CHECKINTERVAL;
   2442         fs->super->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT;

   2443         /*
   2444          * Add "jitter" to the superblock's check interval so that we
   2445          * don't check all the filesystems at the same time.  We use a
   2446          * kludgy hack of using the UUID to derive a random jitter value
   2447          */
   2448         for (i = 0, val = 0 ; i < sizeof(fs->super->s_uuid); i++)
   2449             val += fs->super->s_uuid[i];
   2450         fs->super->s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT;


And we can see the MAX_MNT_COUNT is just a precompiler definition:

"lib/ext2fs/ext2_fs.h"
    519  * Maximal mount counts between two filesystem checks
    520  */
    521 #define EXT2_DFL_MAX_MNT_COUNT      20  /* Allow 20 mounts */


So we take 20, add up all the ASCII characters of the UUID and modulo that by 20, then add it to the original 20. It's just maths from here. 20+(x%20) gives an effective range of 20 to 39 days.

We can also tell from the comment in mke2fs.c as to the reason behind this randomness.

Thursday, August 29, 2013

finding the netdev_priv struct

In addition to the net_device struct within the kernel, network drivers also have their own private or device-specific struct which stores stats unique to the individual hardware.

The name of the struct varies for each device type, however the location remains the same, right after net_device:

linux-2.6.32-358.14.1.el6.x86_64/include/linux/netdevice.h:L1343

/**
 *      netdev_priv - access network device private data
 *      @dev: network device
 *
 * Get network device private data
 */
static inline void *netdev_priv(const struct net_device *dev)
{
        return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
}


A search in cscope for netdev_priv will show you many functions within drivers which update the priv structure via pointers, for example this one in e1000_main.c:

struct e1000_adapter *adapter = netdev_priv(netdev);

So, given that we know what the device-specific struct is called, and where the device-specific private struct is, how do you find it and read it?

We'll need the ability to read kernel memory using crash, either run on a live system, or in a vmcore captured with kdump:

crash /usr/lib/debug/lib/modules/2.6.32-358.14.1.el6.x86_64/vmlinux /var/crash/2013-08-26/vmcore

We'll also need the debugging symbols for the driver in question:

crash> mod -s e1000 /usr/lib/debug/lib/modules/2.6.32-358.14.1.el6.x86_64/kernel/drivers/net/e1000/e1000.ko.debug
     MODULE       NAME                 SIZE  OBJECT FILE
ffffffffa01550e0  e1000              170678  /usr/lib/debug/lib/modules/2.6.32-358.14.1.el6.x86_64/kernel/drivers/net/e1000/e1000.ko.debug



The net command will show you the network devices in the system:

crash> net
   NET_DEVICE     NAME   IP ADDRESS(ES)
ffff88007e76b820  lo     127.0.0.1
ffff8800372c0020  eth0   192.168.1.126


We can then cast net_device against this to see the in-kernel device struct:

crash> net_device 0xffff8800372c0020
struct net_device {
  name = "eth0\000\000\060:03.0\000\000\000",

...

But we want to get after this struct and cast it against the struct in the driver.

We need to know how big net_device is:

crash> struct -o net_device
struct net_device {
...

}
SIZE: 1728


We then find the net address plus the size of net_device:

crash> px 0xffff8800372c0020+1728
$1 = 0xffff8800372c06e0


We can now cast the device-specific private struct against this new address:

crash> e1000_adapter 0xffff8800372c06e0
struct e1000_adapter {
  vlgrp = 0x0,
  mng_vlan_id = 65535,
  bd_number = 0,
  rx_buffer_len = 1522,
...


and we're done!