Thursday, January 17, 2019

local DNS resolver, forwarding LAN/DHCP domain to your plasic router

I have a setup which should be typical of the usual computer-savvy person's home network.

  • residential DSL line, using a "plastic router" (CPE, customer premises equipment), in my case, a "FritzBOX" from AVM
  • computers I work on (Laptop, Desktop)
  • server machines I run services on
The local router provides routing (obviously) and hands out IP addresses via DHCP (V4) and stateless IPv6 autoconfiguration, but it also manages a local DNS server synchronized to the DHCP leases (domain fritz.box.). It also registers its external IP address with a dynamic DNS provider, so that I have an externally visible DNS record point to its IPv4 address. I have a static IPv6 address provided by a tunnel provider.

To my local server machine I can SSH from the outside, using the dynamic IPv4 address updated by the router, but also to the static IPv6 address via my tunnel provider:
  • IPv4 from the outside, home.dyn.domain. A = 84.39.93.115 (dynamic)
  • IPv6 from the outside, home.dyn.domain. AAAA = 2001:...:fea3 (static)
Problem 1. When on my local LAN, the local server needs to be acessed using its local IPv4 address, or it's global IPv6 address (e.g. 172.17.2.8 (local) and the IPv6 address above 2001:...:fea3 (static)). I can't connect to the local IPv4 address of my server via the dyndns hostname, as I cannot reach 84.29.93.115 from within my LAN, but that's what the SSL certificate is issued to, so I get a warning when using the local IPv4 address.

Problem 2. The DNS resolver of the "Fritz!BOX" unfortunately forwards to a stupid DNS server which cannot resolve via IPv6 DNS servers (it can resolve IPv6 addresses via IPv4 servers, though).

What I want, therefore, is a 2nd IPv6 aware DNS server which fowards the local LAN domain (fritz.box) to the plastic router, resolves IPv6 addresses.

Problem 3. My provider's DNS is a single point of failure, and doesn't even support DNSsec.

Solution: Run my own DNS resolver, but the local LAN (fritz.box) domain is below box., so I have to disable DNSsec for those particular domains.
  • correctly forwards local LAN domains ("fritz.box") and reverse DNS to plastic router
  • replaces external dynamic DNS IPv4 with local LAN IPv4 address
  • acts as a caching resolver, without resorting to broken ISP DNS server
; local resolver

$ host home.dyn.vogel.cx
home.dyn.vogel.cx has address 192.168.178.117
home.dyn.vogel.cx has IPv6 address 2001:XXX...

; google DNS (external)
$ host home.dyn.vogel.cx 8.8.8.8
home.dyn.vogel.cx has address 84.39.93.115
home.dyn.vogel.cx has IPv6 address 2001:XXX...


; local LAN domains

$ host optiplex980.fritz.box
optiplex980.fritz.box has address 172.17.2.8
optiplex980.fritz.box has IPv6 address 2001:XXX...

; local LAN reverse
$ host 172.17.2.8
8.2.17.172.in-addr.arpa domain name pointer optiplex980.fritz.box.




Configuration

/etc/named.conf


logging {
        category default { default_syslog; };
        category unmatched { null; };
};

key "rndc-key" {
        algorithm "hmac-sha256";
        secret "XXX";
};

controls {
        inet 127.0.0.1 port 953 allow {
                127.0.0.1/32;
        } keys {
                "rndc-key";
        };
};

options {
        directory "/var/named";
        hostname none;
        listen-on-v6 { "any"; };
        pid-file "/run/named/named.pid";
        querylog no;
        server-id none;
        version none;
        allow-recursion {
                127.0.0.1/32;    /* localhost */
                ::1/128;
                10.0.0.0/8;      /* RFC1918 */
                172.16.0.0/12;
                192.168.0.0/16;
                169.254.0.0/16;  /* link-local */
                fe80::/16;
                fd00::/16;
                2001:XXX:XXX:XXX::/64; /* local IPv6 Prefix */
        };
        allow-transfer { none; };
        allow-update { none; };
        empty-zones-enable no;
        stale-answer-enable yes;

        /* didn't find this in the manual, but in the changelog
           to BIND 9.13.3, this option specifies a list of domains
           beneath which DNSSEC validation should not be performed */
        validate-except {
                "fritz.box";
                "fritz.nas";
                "wpad.box";
        };
};

zone "localhost" IN {
        type master;
        file "localhost.zone";
};
zone "0.0.127.in-addr.arpa" IN {
        type master;
        file "127.0.0.zone";
};
zone "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" {
        type master;
        file "localhost.ip6.zone";
};
zone "255.in-addr.arpa" IN {
        type master;
        file "empty.zone";
};
zone "0.in-addr.arpa" IN {
        type master;
        file "empty.zone";
};
zone "." IN {
        type hint;
        file "root.hint";
};

# --- resolve our "dynamic DNS" correctly to the internal ---
# --- ip addresses (which are obviously not dynamic) ---

zone "dyn.XXX.XXX" IN {
        type master;
        file "dyn.XXX.XXX.zone";
};

# --- local plastic "router" is managing these zones ---

# fritz.box
zone "fritz.box" IN {
        type forward;
        forward only ;
        forwarders { 172.17.2.1; };
};

zone "wpad.box" IN {
        type forward;
        forward only ;
        forwarders { 172.17.2.1; };
};

zone "fritz.nas" IN {
        type forward;
        forward only ;
        forwarders { 172.17.2.1; };
};
# 172.17.2/24
zone "2.17.172.in-addr.arpa" IN {
        type forward;
        forward only ;
        forwarders { 172.17.2.1; };
};

# 2001:XXXXX::/64
zone "X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.ip6.arpa" IN {
        type forward;
        forward only ;
        forwarders { 172.17.2.1; };
};

# fd00::/64
zone "0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.f.ip6.arpa" IN {
        type forward;
        forward only ;
        forwarders { 172.17.2.1; };
};


/var/named/dyn.XXX.XXX.zone


@ 86400 IN SOA home hostmaster (
                2018110401 ;serial
                10800      ;refresh
                1800       ;retry
                604800     ;expire
                86400      ;minimum
        )

@       IN NS   home
@       IN MX 10 home

; local addresses of my home server
home IN A 192.168.178.117
home IN AAAA 2001:XXX:XXX:XXX:XXX:XXX:XXX:XXX


Saturday, January 05, 2019

i2c on your unused/legacy VGA output

Almost every PC/notebook still has a VGA connector, which can be used as a very cheap way to quickly test various i2c peripherals. On a VGA connector, it would have been used to query the remote monitor for its supported resolutions, but most graphics drivers in Linux just use the
kernel's generic i2c support.

This is a quick note for myself, so that I can easily copy & paste whenever needed again ;-).

From the linked Wikipedia page:

Pin 9 KEY/PWR formerly key, now +5V DC, powers EDID EEPROM chip on some monitors
Pin 10 GND Ground (VSync, DDC)
Pin 12 ID1/SDA formerly Monitor ID bit 1, I²C data since DDC2
Pin 15 ID3/SCL formerly Monitor ID bit 3, I²C clock since DDC2

Step 1, make sure your graphics card actually exports this i2c device (check the names of all busses in /sys/bus/i2c/devices).

$ grep "" /sys/bus/i2c/devices/i2c-*/name
/sys/bus/i2c/devices/i2c-0/name:SMBus I801 adapter at 0580
/sys/bus/i2c/devices/i2c-1/name:i915 gmbus ssc
/sys/bus/i2c/devices/i2c-2/name:i915 gmbus vga
/sys/bus/i2c/devices/i2c-3/name:i915 gmbus panel
/sys/bus/i2c/devices/i2c-4/name:i915 gmbus dpc
/sys/bus/i2c/devices/i2c-5/name:i915 gmbus dpb
/sys/bus/i2c/devices/i2c-6/name:i915 gmbus dpd
/sys/bus/i2c/devices/i2c-7/name:DPDDC-B
/sys/bus/i2c/devices/i2c-8/name:DPDDC-C



Step 2, make sure a user can conveniently access this bus without becoming root.

$ cat /etc/udev/rules.d/99-i2c-vga-chmod.rules 
ACTION=="add", SUBSYSTEM=="i2c-dev", ATTR{name}=="i915 gmbus vga", MODE="0660", GROUP="users", SYMLINK+="i2c-vga"

#
# udevadm info -a -p \$(udevadm info -q path -n /dev/i2c-2)
#
# Udevadm info starts with the device specified by the devpath and then
# walks up the chain of parent devices. It prints for every device
# found, all possible attributes in the udev rules key format.
# A rule to match, can be composed by the attributes of the device
# and the attributes from one single parent device.

#   looking at device '/devices/pci0000:00/0000:00:02.0/i2c-2/i2c-dev/i2c-2':
#     KERNEL=="i2c-2"
#     SUBSYSTEM=="i2c-dev"
#     DRIVER==""
#     ATTR{name}=="i915 gmbus vga"

#   looking at parent device '/devices/pci0000:00/0000:00:02.0/i2c-2':
#     KERNELS=="i2c-2"
#     SUBSYSTEMS=="i2c"
#     DRIVERS==""
#     ATTRS{name}=="i915 gmbus vga"
(...)

Step 3, make sure the i2c-dev kernel module is loaded upon boot.

$ cat /etc/modules-load.d/i2c-dev.conf 

i2c-dev

Step 4, solder a matching cable from 15pin DSUB to whatever is convenient for you, I suggest some individual connectors for pin headers.




Step5, Profit!

(I'm using a HYT271 humidity and gemperature sensor for testing, it's showing 39 %rh and 26 °C, the small utility is by David Wragg and to be found on github.)





It should be noted that this will obviously work almost identical on DVI/DisplayPort/HDMI outputs, your motherboard's SMBUS, your random USB peripheral that exposes an i2c bus, ...

A quick warning, these i2c-busses are often bit-banged and will consume a considerable amount of cycles on your 3Ghz Octacore i7 while clocking out a few kBits/second via i2c. :-)

Saturday, May 12, 2018

Behringer X32 and S16 Preamp Noise

I got myself a Behringer X32 Compact mixing desk and Behringer S16 Stageboxes. Because sometimes I record classical concerts, or have ambient microphones that get very little signal, I wanted to verify the preamp performance to avoid nasty surprises.

To establish the voltage scale when recording, a sine-generator generating 1kHz was fed into a passive DI box, and adjusted in amplitude, so that a 1Vrms signal was present on the DI box XLR output. This 1Vrms signal could be easily measured with a TRMS multimeter. Then both the 20dB pad on the DI-box and a 40dB pad on the function generator were engaged, so that a 1mVrms signal is output on the DI box. This sinewave was fed into all devices under test at maximum gain. (See Fig. 2)

Sucessively the XLR connection to the DI box was removed and the input was shorted. A 2nd recording was then made, with identical gain settings only capturing the noise. (See Fig. 1)

Preamps tested were:
  • EchoAudio EchoFire 4, which uses a now obsolete SSM2017 from which noise performance is known and documented
  • Preamps within the X32 Compact mixing console, using the local XLR input
  • Preamps within the two S16 stage boxes
In python (using numpy), the rms of the sinewave-recording was calculated relative to digital full-scale and the noise recording scaled with the resulting factor (e.g. -21.0 dBrms/full-scale for the EchoFire4 recording). From this data the noise density in nV/√Hz was calculated using Scipy's scipy.signal.welch results.

The spikes present are most likely caused by switching voltage regulators within, or in vincinity of, the devices. Generally the Behringer preamps have slightly higher noise than the very respectable SSM2017 within the EchoAudio firewire interface, but all in all the difference is pretty much irrelevant (approx. ~1.5dB more noise than the  SSM2017, adds approx. 3 dB to the thermal noise of the 200Ω resistor) for practical use.


Fig1: Noise Analysis (with inputs shunted by 200Ω)

Fig2: Reference Recording of 1mVrms, 1kHz Sine Wave

Useful Links

Monday, September 11, 2017

VHDL Testbench using Oscilloscope Waveforms

I got a little tired of writing a generator for synthetic data in a VHDL testbench, so I thought, maybe just use an oscilloscope trace with real-workd data for this purpose.

So, here's the VHDL code, I've only captured one channel and it's stored as unsigned 8-bit characters, so everything is very easy.



signal aes3_in : std_logic;
signal aes3_analog : natural;
type t_stim_file is file of character;
data_in: process
   -- waveform captured on a rigol oscilloscope, 1ch, 8bit, 1GS/s
   file stim_file : t_stim_file open read_mode is "aes_48khz_24bit.wfm";
   variable v : character;
   variable n : natural range 0 to 255;
begin
   -- skip over the first 3300 bytes, header of the wfm file
   for i in 0 to 3300 loop
      read(stim_file, v);
   end loop;
   while not endfile(stim_file) loop
      read(stim_file, v);
      n := character'pos(v);
      aes3_analog <= n;
      aes3_in <= '1' when n > 90 else '0';
      wait for 1 ns; -- 1GHz sampling rate
   end loop;
   assert false report "end of test" severity failure; -- end testbench here
end process;



Monday, July 24, 2017

Mixing Station X Air Pro XR18 Default Layout

Working with a Behringer XR18 Mixer and using the brilliant Mixing Station Air software, I've made a custom layout for it. It can be downloaded from github.


Thursday, March 23, 2017

Roland TD-25 (Drum Sound Module) Pinout and Waveforms

Debugging an issue with a Roland TD-25K electronic drum set.

First, here are the outputs of the trigger-pads. Yellow is "tip" of a TRS connector, cyan is "ring". Both the bell and the dampening signals of the cymbals connect to the ring and there's a constant voltage offset (which you don't see because the 2nd (cyan) channel was AC coupled.

PDX-100 Snare Pad



CY-13R Ride Cymbal, "Cymbal" connector:



Ride Cymbal, "Bell" connector:



Also, I traced the pinout of the Roland TD-25 multipin/dsub connector.


                   /--+
                +-/   |
                |   O |  1 KIK-T
   T1-T      14 | O   |
                |   O |  2 KIK gnd
   T1-R      15 | O   |
                |   O |  3 SNR-T
   T1 gnd    16 | O   |
                |   O |  4 SNR-R
   T2-T      17 | O   |
                |   O |  5 SNR gnd
   T2-R      18 | O   |
                |   O |  6 HH+T2 gnd
   T3 gnd    19 | O   |
                |   O |  7 HH-T
   T3-T      20 | O   |
                |   O |  8 HH-R
   T3-R      21 | O   |
                |   O |  9 HHC gnd
  RD/RDB gnd 22 | O   |
                |   O | 10 HHC-T
  RD-R       23 | O   |
                |   O | 11 CR1 gnd
  RD-T       24 | O   |
                |   O | 12 CR1 T
  RDB-R      25 | O   |
                |   O | 13 CR1 R
                +-\   |
                   \-+

gnd: sleeve/ground, T: tip, R: ring
T1/T2/T3: Tom 1, 2, 3
RD: Ride
RDB: Ride Bell
HH: Hihat
HHC: Hihat pedal
KIK: Kick/Bassdrum
SNR: Snare
CR1: Crash Cymbal




Wednesday, November 09, 2016

Archlinux on the Toradex T20 (with Archlinux' kernel)

This is a followup on my earlier blogpost Archlinux on the Toradex T20 from 2012.

I happened to resurrect my old Toradex NVidia Tegra T20 / Colibri / Iris eval-board, which I had running using Toradex' kernel back in 2012 already. And it's amazingly smooth to run the stock Archlinux-Arm distribution for ARM7 CPUs on it, as I found out:

You'll need:

  • a SD-card formatted using the EFI partition table format (the stock uboot for whatever reason didn't like it when I had it partitioned as MBR)
  • two partitions, one for boot, one for the rest (I used vfat / ext4)
  • mkfs.vfat on the first partition (will be mmcblock0p1 on the Toradex), mkfs.ext4 for the 2nd.
  • mount the first partition (vfat) as "boot" in the second partition (ext4, rootfs)
  • unpack http://os.archlinuxarm.org/os/ArchLinuxARM-trimslice-latest.tar.gz in the 2nd partition
  • in "boot" create a uImage from the zImage (the stock u-boot of Toradex can't boot zimages directly), I use the following script (on the toradex module itself, useful after a kernel upgrade!) You'll need the "mkimage" utility from uboot-tools.
[root@alarm ~]# cat /usr/local/sbin/mkuimage.sh 
#!/bin/sh

mkimage -A arm -O linux -T kernel -C none \
-a 0x00008000 -e 0x00008000 \
-n "Linux Kernel" -d /boot/zImage /boot/UImage

Interrupt the bootloader (in the stock configuration, bootdelay is zero, so you'll have to hit your keys hard to get it to interrupt the boot!) and configure the following environment variables like so:

(copy & paste every line separately, I got lost characters when I paste then as a whole!)

env default -f
setenv dtaddr 0x1000000
setenv dtbname tegra20-iris-512
setenv myload_img fatload mmc 0:1 \${loadaddr} uimage
setenv myload_fdt fatload mmc 0:1 \${dtaddr} dtbs/\${dtbname}.dtb \; fdt addr \${dtaddr}
setenv myload mmc part\;run myload_img\;run myload_fdt
setenv myargs setenv bootargs console=ttyS0,115200 root=/dev/mmcblk0p2 rootdelay=2
setenv myboot run myargs \; run myload \; bootm \${loadaddr} - \${dtaddr}
setenv bootcmd run myboot
setenv bootdelay 5
saveenv

If you just want to test, leave out the last "saveenv" and type "run myboot", after a reset, your Toradex module will still be completely unchanged. If you save the environment (u-boot configuration) with "saveenv", the module should boot up archlinux automatically.

Update: I just realized, the variable "fdtaddr" I used initially is used by u-boot internally and overwritten on every boot, don't use it then :-).

Bootup:

U-Boot 2011.06-dirty (Dec 18 2014 - 22:27:35)

TEGRA2
DRAM:  512 MiB
NAND:  1024 MiB
MMC:   Tegra2 SD/MMC: 0
Board: Toradex Colibri T20
Net:   Net Initialization Skipped
No ethernet found.
Hit any key to stop autoboot:  0 

Partition Map for MMC device 0  --   Partition Type: EFI

Part  Start LBA  End LBA
gpt1  0x800    0x407FF
gpt2  0x40800    0x1D47BDE
reading uimage

5623992 bytes read
reading dtbs/tegra20-iris-512.dtb

28979 bytes read
## Booting kernel from Legacy Image at 00408000 ...
   Image Name:   Linux Kernel
   Created:      2016-11-08  21:31:41 UTC
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    5623928 Bytes = 5.4 MiB
   Load Address: 00008000
   Entry Point:  00008000
   Verifying Checksum ... OK
## Flattened Device Tree blob at 01000000
   Booting using the fdt blob at 0x1000000
   Loading Kernel Image ... OK
OK
   Loading Device Tree to 01ff5000, end 01fff132 ... OK

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 4.8.6-1-ARCH (builduser@leming) (gcc version 6.2.1 20160830 (GCC) ) #1 SMP Mon Oct 31 23:22:19 MDT 2016