Epson 3490 Scanner

This is an information that tends to be forgotten on the Internet, so I’m publishing it here. How to get an Epson Perfection 3490 Photo scanner running under Linux, FreeBSD or whatever. Paths may change on your system, so you may need to adapt the instructions below.

1. Install xsane.

2. Download the Epson firmwares. For the Epson 3490, you need esfw52.bin. You may find this file on Internet, although it tends to disappear. But in any case you can also find this file here.

3. Uncompress the firmwares. That is, sudo tar -Jxvf epson-firmwares.tar.xz -C /usr/local/share/sane.

4. Modify /usr/local/etc/sane.d/snapscan.conf, change the firmware line to point to the esfw52.bin firmware. That is following the commands above, change the firmware line to firmware /usr/local/share/sane/epson-firmwares/esfw52.bin.

If you are running FreeBSD

You should still ensure that you can use the scanner as a normal user.

5.Let’s change the owner of the scanner so that it’s available to users in the saned group. Create /etc/devd/saned.conf and add:

notify 100 {
  match "system" "USB";
  match "subsystem" "INTERFACE";
  match "type" "ATTACH";
  match "cdev" "ugen[0-9].[0-9]";
  match "vendor" "0x04b8";
  match "product" "0x0122";
  action "chown -L cups:saned /dev/$cdev && chmod -L 660 /dev/$cdev";

Notice the 0x4b8:0x0122, identifying the scanner USB device which you can get from the lsusb command while the scanner is plugged in.

6.Restart devd with service devd restart.

7.Add yourself to the saned group with sudo pw groupmod saned -m

8.You may need to log in again so that new group changes are taken into account.

Disable XF86Back/Forward

Real ThinkPad keyboards (not this monstruous ignominy) have directly accessible keys for XF86Back and XF86Forward. That is really problematic with web browsers such as Firefox or Chromium since pressing those keys transparently go back or forward into your history, discarding anything you were typing in the process, including that 3 hours long bug report you were just about to submit. That’s rather annoying, to say the least.

Some other blog post suggest to simply disable them with xmodmap. That is in ~/.xmodmaprc (or whatever it is you use):

keycode 166 = NoSymbol
keycode 167 = NoSymbol

I personally prefer to remap them to Next/Prior keys. Having these near the navigation keys might come up handy:

keycode 166 = Next
keycode 167 = Prior

That’s on Linux though, on FreeBSD the keycodes are 233 and 234:

keycode 233 = Next
keycode 234 = Prior

Anyway use the xev command and xmodmap -pke to find the keycodes and remap them to any other interesting key symbol.

Hide logs from wheel users

If you have grown accustomed to FreeBSD administration, you’ve probably learned that users need to be member of the wheel group to be able to use the su command. Some in the land of GNU don’t agree so much with this way of doing and firmly believe that wheel is an instrument of power (which is true in a literal sens) but that’s another story.

In fact I am perfectly fine with this save for one little detail. By default most log files are owned by root:wheel. Altough while some of them have permission 600, a lot of them are 640 which means that members of the wheel group will be able to read them. We have basically two solutions to fix this:

  • Fix permissions in /etc/newsyslog.conf.
  • Use another group instead of wheel for the su command.

Fixing newsyslog.conf is quite easy, just replace the mode column with any permission you fancy (in our case 600). Don’t forget to restart newsyslog and fix existing permissions with find /var/log -type f -exec chmod 600 {} \;.

However that might not be enough. You see on most BSD wheel has gid 0, whereas on Linux it is root that has gid 0. Nobody is supposed to be a member of root, but it serves as a general purpose group for anything owned solely by root. As such you can often use chown 0:0 as a synonym of owned by root.

But root:root on Linux would not have the same meaning as root:wheel on BSD. In particular you can generally suppose that files owned by root:root with permission 640 on Linux are only readable by the root user but the same supposition doesn’t translate so well for us BSD users.

While I’m not keen of importing such kind of Linuxism into FreeBSD, one way to deal with it would be to use another group for su users. For this we would:

  • Create the su system group.
  • Move all members of wheel to this group.
  • Modify /etc/pam.d/su to use group=su instead of group=wheel.

Now I don’t personally do that, but I guess what you do it’s your business.

Custom user Xsession with SDDM

Debian stretch is out, a lot of obsolete packages, a lot of major upgrades, which all in all resulted in quite a painful transition the last few days. But I’ll tell you more about that in the following posts.

I don’t really spend much time on Linux nowadays so KDE (along with KDM) has always been my goto solution for a jack all trade no-BS works-out-of-the-box desktop environment. And it worked like that just fine, until… well you know how software goes. KDE has been upgraded, KDM has been depreciated and replaced with SDDM.

I also use xsession so that I have a common way of starting session scripts and daemons (such as this one) and configuring stuff across different desktops. I generally selected custom session in the display manager and that was it. But SDDM does not seem to provide a way to do so, or at least that’s not so clear.

By default, it will execute /etc/sddm/xsession which itself sources /etc/X11/Xsession to which it will pass as argument the value of the Exec line in the desktop file (located in /usr/share/xsessions) describing the currently selected session.

If we want to bypass this, we need to scrap the argument passed to /etc/X11/Xsession no matter what SDDM thinks the current session should be. To do so create a wrapper for Xsession in /etc/X11/user-Xsession:


export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin

# Discard argument, we don't care about selecting the desktop environment.

And now configure SDDM to use this instead of its own version of it, in /etc/sddm.conf:


Using NAT64 locally

NAT64 is a translation mechanism that allows IPv6 addresses to be transparently mapped to IPv4 addresses. The principle if very simple. In a NAT64 address, the IPv4 address is embedded into the 32 least significant bits of the IPv6 address. When you send an IPv6 packet to a NAT64 router, it will extract the IPv4 address embedded into the NAT64 IPv6 destination address and send the packet using this IPv4 instead. The source IPv4 address used is chosen within a provided pool of IPv4 addresses (which can be SNATed, in which case you can use a private network reserverd for the NAT64 pool). The NAT64 router will also do the reverse mapping and translate the reply from the IPv4 remote address to your original IPv6 address.

This is very convenient for IPv6 only hosts (such as IoT smart objects) that need to contact a very sparse IPv6 Internet. Even if a remote host is only accessible via IPv4, it can still be accessed from IPv6 using its NAT64 address. Also since the majority of addresses are resolved using DNS, there are some servers (unbound is one of them) that provide a DNS64 module which will automatically construct a NAT64 AAAA record when no other IPv6 records are found for a specific domain. This way your IPv6 only hosts using DNS believe that all domains have an AAAA record, and that all the Internet is IPv6 enabled.

In my case I use Tayga NAT64 router along with Unbound DNS64 module. There are several posts out there that explain how to configure these two and this is not my intent here. Instead I want to focus on a problem that I had using Tayga’s NAT64 locally. That is trying to ping a non-IPv6 domain from the host that is running Tayga:

$ ping6

This command worked fine from outside the host running Tayga (for packets routed through the NAT64 router), but didn’t work at all when issued on the host running Tayga.

Using tcpdump, I found that when issued locally, Tayga used its own IPv4 address (its ipv4-addr option) as source address for the translated IPv6 packets. Since this address was not mapped in Tayga IPv4 source address pool, it did not translate the reply back to the original IPv6 address and so the ping6 command never got any reply.

What I also found was that the source address used by the ping6 command was also Tayga’s own IPv6 address (its ipv6-address option). Since the NAT64 address that ping6 tries to use is routed through the nat64 interface, it defaulted to the nat64 interface IPv6 address (that is Tayga’s IPv6 address) for its source address.

This is what triggered Tayga to use its own IPv4 address which is outside its pool resulting in the reply not being translated back to its own IPv6 address. So we need a way to avoid choosing Tayga’s own IPv6 address when trying to reach a NAT64 address locally. We know that Tayga configures its own IPv4 and IPv6 addresses on its nat64 interface. All we have to do is to add another IPv6 address to the interface so that it will be used instead as the source address for local packets destinated to the nat64 router interface.

Suppose we have:

  • Internet routed prefix: 2001:db8:1::/64
  • NAT64 IPv6 prefix: 2001:db8:64::/96
  • NAT64 IPv6 address: 2001:db8:1::64
  • NAT64 IPv4 address:

Then the nat64 interface will have the 2001:db8:1::64 IPv6 address. Just add another IPv6 address to this interface with:

ifconfig nat64 inet6 add 2001:db8:1::46 netmask 128

Tadaaa! Now when you try to reach a NAT64 address locally, the address you just added to nat64 will be used instead as the source address. Since this is not Tayga’s own IPv6 address, it will dutifully map the NAT64 using its IPv4 address pool and translate the reply back to the new IPv6 address. In other words NAT64 addresses now work on the host running the NAT64 router.

Linuxulator ist kaputt

Since a few weeks I’m running RELEASE on a custom kernel to use a patch that I made for a missing feature in the IPv6 stack (namely icmp_may_rst).

But a few minutes ago I had the surprise to find that the Linuxulator was no longer working. Trying to run a Linux binary failed with the following error:

ELF binary type "0" not known.
exec: test: Exec format error

Actually looking at kldstat, the Linux kernel module wasn’t even loaded. Trying to load it manually gave me the following error:

link_elf_obj: symbol kern_sched_setscheduler undefined
linker_load_file: Unsupported file type

OK so what is this sched_setscheduler you are talking about? Well there you go!
Now the Linuxulator depends on that syscall, but for some reason the necessary option disappeared from my custom kernel configuration. All I had to do was to add it again and recompile:

options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions

And now I can run Linux binaries again!

Redirect traffic to loopback

Today I wanted to transparantly redirect the DNS requests coming at the output of a tunnel to a local caching DNS resolver. The caching DNS was listening only on the loopback as port 53 was already bound to other interfaces. That would be fairly simple on Linux:

echo 1 > /proc/sys/net/ipv4/ip_forward

iptables -t nat -A PREROUTING -i tun0 -p udp --dport 53 -j DNAT --to-destination
iptables -A FORWARD -i tun0 -o lo -p udp --dport 53 -j ACCEPT

But… The kernel will refuse to route packets with the loopback as source or destination because this qualify as a martian packet. The solution was to enable the route_localnet flag. As stated in the kernel documentation:

route_localnet – BOOLEAN: Do not consider loopback addresses as martian source or destination while routing. This enables the use of 127/8 for local routing purposes (default FALSE).

This is per interface. So I just had to enable this on the tunnel interface:

echo 1 > /proc/sys/net/ipv4/conf/tun0/route_localnet

Rename interfaces on Linux

I just reinstalled a Debian stable on a laptop but messed with the interfaces so that an external USB WiFi card appeared as wlan0 while the main card appeared as wlan1. In case you wondered you can rename or reset interface names in /etc/udev/rules.d/70-persistent-net.rules. That’s on systemd though.
I wonder how we can change that on sysvinit? Nobody cares, probably, but I do.

According to what I read there, it is not consistent. Interfaces are named in the order in which they appear during the boot process. However it is possible to use ifrename from the wireless tools package. Why this tool that should work for all type of interface is part of the wireless tools package is beyond my comprehension. But hey whatever, Linux, and it just works.

If you are curious and want to know how ifrename actually does rename an interface, according to the code it uses a SIOCSIFNAME ioctl on a socket file descriptor. There it passes a struct ifreq in which you can provide a new name for the interface. Just man netdevice(7) for more info.

Constant SD-Card corruption on the RPi

Our home servers broke. Here we are again.

I spent weeks of my time, countless evenings up to 4AM, entire weekends since months trying to design and configure our reborn home-servers and gateways.

And it was neat.

  • DNSSEC all the way down
  • RPC accross the nodes
  • Easy configuration
  • Caching and stuff
  • Automatic tests

It took me a lot of time to assemble all of this in something that I liked. And to document everything so that we could easily install a new node from scratch.

I installed two nodes and it worked well for several weeks. Until a week ago or so I started to see corruption on the first node. And by corruption I mean random garbage in a lot of binaries and libraries. Exec format error at every corner. At this point it was completely broken and useless so the only option was to reinstall it.

So I used a new SD-Card, changed the power supply and reinstalled everything last weekend. Just finished today and also fixed bugs in some of our scripts. Had to search for a package on the second node which at this point was still in a pretty good shape.

$ apt-cache
zsh: exec format error: apt-cache
$ su
zsh: exec format error: su

Dang! So there goes another weekend I will spend to reinstall the thing. And who knows how long until the first node gets corrupted again.

Checked the TP1-TP2 voltage, 4.65V, probably because of the second USB Ethernet adapter. I tried to limit the amount of writes on the SD-Card. No heavy writers, no swapping, no overclocking.

So I must be doing something wrong, right? Right?! The RaspberryPi can be that unreliable. I wonder how many power supplies and SD-Cards I will have to buy and try until, by sheer luck, I do not have to reinstall everything in the following three months or so.

I ran into this problem years ago. And now it seems that I will run in the same problem over and over again. Any recommendation is welcome of course. Though to be honest, for now, I just want to fly the damn thing across the room.