Wednesday, February 28, 2007

Scanner Darkley

Getting remote scanning to work seemed easy enough at first...
  1. Install the sane network daemon (and other stuff):
    # apt-get install sane-utils
  2. Follow the instructions outlined in the man page, namely:
    • add a line for saned in /etc/inetd.conf
      sane-port stream tcp nowait saned.saned /usr/sbin/saned /usr/sbin/saned
    • specify a list of allowed clients in /etc/sane.d/saned.conf
    • restart inetd with
      # /etc/init.d/openbsd-inetd restart
  3. Install SaneTwain on my wife's laptop and configure it to connect to my laptop
  4. Add a line to /etc/shorewall/rules to accept connections on the saned control port 6566, and restart the firewall with
    # /etc/init.d/shorewall restart

But it didn't work. Specifically, SaneTwain was able to query the type of the scanner and its parameters, but failed to acquire a preview.

It turns out that the scanned data isn't transferred thru the saned control port, but rather thru a different, dynamically set port. This is actually mentioned in the man page under the restrictions section, and their suggestion is
"If you must use a packet filter, make sure that all ports > 1024 are open on the server for connections from the client"
which seems like a bad idea.

The interim solution to the problem, until proper saned connection tracking is available, is outlined on the Gentoo-Wiki, and here is how I implemented it with shorewall:
  1. create an empty file /etc/shorewall/action.SaneConntrack
  2. create a file /etc/shorewall/SaneConntrack

    # track SANE control connections
    run_iptables -A $CHAIN -m recent --update --seconds 600 --name SANE
    # related traffic (ACK, FIN, DNS UDP responses etc.)
    run_iptables -A $CHAIN -m state --state ESTABLISHED,RELATED -j ACCEPT
    # SANE server uses a dynamic data port above 1024
    run_iptables -A $CHAIN -p tcp -m tcp --dport 6566 --syn -m recent --set --rsource --name SANE -j ACCEPT
    run_iptables -A $CHAIN -p tcp -m tcp --dport 1024: --syn -m recent --rcheck --rsource --seconds 3 --name SANE -j ACCEPT

  3. Add a line to /etc/shorewall/actions (create the file if it does not exist):
  4. Add the following lines to /etc/shorewall/rules
    # saned
    SaneConntrack loc $FW tcp 6566
    SaneConntrack loc $FW tcp 1024:
  5. Restart shorewall.
Simple, right?


  1. Thanks for thie. I was very helpful. To make this work for me I had to change step 4 from:

    SaneConntrack loc $FW tcp 6566
    SaneConntrack loc $FW tcp 1024:


    SaneConntrack net $FW tcp 6566
    SaneConntrack net $FW tcp 1024:

  2. Just a note for anyone who tries to use these directions in Shorewall 4.0 or later: if you're using the Perl based configuration compiler, then these steps won't work. The stuff in step 2 is written for the Bourne Shell based config compiler, which is now optional in SW 4.0, and will be phased out.

    Perhaps Zung could get ahead of the inevitable Shorewall update for Debian and rewrite the directions to use the Perl compiler.

  3. Maybe take a look at Shorewall-perl ?
    Seems to be a decent starting point.

    Try the following (untested):

    use Shorewall::Chains;

    # track SANE control connections
    add_rule $chainref, "-m recent --update --seconds 600 --name SANE";
    # related traffic (ACK, FIN, DNS UDP responses etc.)
    add_rule $chainref, "-m state --state ESTABLISHED,RELATED -j ACCEPT";
    # SANE server uses a dynamic data port above 1024
    add_rule $chainref, "-p tcp -m tcp --dport 6566 --syn -m recent --set --rsource --name SANE -j ACCEPT";
    add_rule $chainref, "-p tcp -m tcp --dport 1024: --syn -m recent --rcheck --rsource --seconds 3 --name SANE -j ACCEPT";


    I'm definitely not getting into this before I have to. I simply don't have the time, sorry.

  4. zung! -

    Your shorewall-perl action worked fine for me.