vim, screen, and bracketed paste mode

A little while back an update was introduced, somewhere, that has been driving me nuts.  I didn’t record exactly when it happened or what changed.  I suppose it doesn’t matter now.

The behavior wasn’t easy to pin down at first since it was the confluence of several things: 1) pasting 2) into vim while 3) using a non-xterm terminal like mate-terminal and 4) inside a screen session.

The behavior exhibits in several ways:

  • Pastes appear to be incomplete, or (more correctly) some number of characters at the beginning of the paste go “missing” and actually become commands to vim
  • Pastes are complete but they’re bracketed with \e[200~content\e[201~
    • some people report 0~content1~ instead, but it appears to be the same phenomenon

What’s going on?  It’s a feature called “bracketed paste mode”.  You can google it read up on it, it has some utility.  As far as I can tell it’s related to readline.  But more importantly, there is a fix.

Add this to your ~/.vimrc:

" fix bracketed paste mode
if &term =~ "screen"
  let &t_BE = "\e[?2004h"
  let &t_BD = "\e[?2004l"
  exec "set t_PS=\e[200~"
  exec "set t_PE=\e[201~"
endif

source: https://vimhelp.appspot.com/term.txt.html#xterm-bracketed-paste

WordPress Error: cURL error 6: Couldn’t resolve host ‘dashboard.wordpress.com’

Background:

I maintain a WordPress blog that uses Jetpack’s Stats package.

Issue:

We started getting this error message when opening the ‘Stats’ page:

We were unable to get your stats just now. Please reload this page to try again. If this error persists, please contact support. In your report please include the information below.

User Agent: 'Mozilla/5.0 (X11; Linux x86_64; rv:54.0) Gecko/20100101 Firefox/54.0'
Page URL: 'https://blog.server.tld/wp-admin/admin.php?page=stats&noheader'
API URL: 'https://dashboard.wordpress.com/wp-admin/index.php?noheader=true&proxy&page=stats&blog=XXX&charset=UTF-8&color=fresh&ssl=1&j=1:5.0&main_chart_only'
http_request_failed: 'cURL error 6: Couldn't resolve host 'dashboard.wordpress.com''

The entire Stats block in the Dashboard was empty, and the little graph that shows up in the Admin bar on the site was empty as well.

Other errors noticed:

RSS Error: WP HTTP Error: cURL error 6: Couldn't resolve host 'wordpress.org'
RSS Error: WP HTTP Error: cURL error 6: Couldn't resolve host 'planet.wordpress.org'

These errors were in the WordPress Events and News section, which was also otherwise empty.

This whole thing was ridiculous on it’s face, as the hosts could all be pinged successfully from said server.

I checked with Jetpack’s support, per the instructions above, and got a non-response of “check with your host.”  Well, this isn’t being run on a hosting service so you’re telling me to ask myself.  Thanks for the help anyway.

Resolution:

The machine in question had just upgraded PHP, but Apache had not been restarted yet. The curl errors don’t make much sense, but since when does anything in PHP make sense?

It was kind of a “duh!” moment when I realized that could be the problem.  Restarting Apache seems to have solved it.

NiFi HTTP Service

I’m attempting to set up an HTTP server in NiFi to accept uploads and process them on-demand.  This gets tricky because I want to submit the files using an existing web application that will not be served from NiFi, which leads to trouble with XSS (Cross-Site Scripting) and setting up CORS (Cross Origin Resource Sharing [1]).

The trouble starts with just trying to PUT or POST a simple file.  The error in Firefox reads:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource (Reason: CORS header 'Access-Control-Allow-Origin' missing).

You can serve up the Javascript that actually performs the upload from NiFi and side-step XSS, but you may still run into trouble with CORS.  You’ll have trouble even if NiFi and your other web server live on the same host (using different ports, of course), as they’re considered different hosts for the purposes of XSS prevention.

handlehttpresponse screen shot
HandleHttpResponse processor config

To make this work, you’ll need to enable specific headers in the HandleHttpResponse processor.  Neither the need to set some headers, nor the headers that need to be set, are documented by NiFi at this time (so far as I can tell).

  1. Open the configuration of the HandleHttpResponse processor
  2. Add the following headers and values as properties and values, but see below for notes regarding the values
    Access-Control-Allow-Origin: *
    
    Access-Control-Allow-Methods: PUT, POST, GET, OPTIONS
    
    Access-Control-Allow-Headers: Accept, Accept-Encoding, Accept-Language, Connection, Content-Length, Content-Type, DNT, Host, Referer, User-Agent, Origin, X-Forwarded-For

You may want to review the value for Access-Control-Allow-Origin, as the wildcard may allow access to unexpected hosts.  If your server is public-facing (why would you do that with NiFi?) then you certainly don’t want a wildcard here.  The wildcard makes configuration much simpler if NiFi is strictly interior-facing, though.

The specific values to set for Access-Control-Allow-Methods depend on what you’re doing.  You’ll probably need OPTIONS for most cases.  I’m serving up static files so I need GET, and I’m receiving uploads that may or may not be chunked, so I need POST and PUT.

The actual headers needed for Access-Control-Allow-Headers is a bit variable.  A wildcard is not an acceptable value here, so you’ll have to list every header you need separately — and there are a bunch of possible headers.  See [3] for an explanation and a fairly comprehensive list of possible headers.  Our list contains a small subset that covers our basic test cases; your mileage may vary.

You may also want to set up a RouteOnAttribute processor to ignore OPTIONS requests (${http.method:equals('OPTIONS')}), otherwise you might see a bunch of zero-byte files in your flow.

References:

[1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

[2] http://stackoverflow.com/questions/24371734/firefox-cors-request-giving-cross-origin-request-blocked-despite-headers

[3] http://stackoverflow.com/questions/13146892/cors-access-control-allow-headers-wildcard-being-ignored

“ERROR: … failed to process… ” in NiFi

I was greeted by a few cryptic things in NiFi this morning during my morning check-in.

  1. A PutSQL processor was reporting an error:
    "ERROR: PutSQL[id=$UUID>]failed to process due to java.lang.IndexOutOfBoundsException: Index: 1, Size: 1; rolling back session: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1"
  2. There were no recent errors counted in the LogAttribute counter we set up to record errors;
  3. The Tasks/Time count in the PutSQL processor was though the roof, despite the errors and lack of successes.

Needless to say, the processor was all bound up and a number of tasks were queued.  Not a good start to my day.

I checked the data provenance and didn’t see anything remarkable about the backed-up data.  The error message suggests (to me) that the first statement parameter is at fault, and that parameter happened to be a date (which has been problematic for me in NiFi with a MySQL backend).  Neither that value, nor the rest of the values, were remarkable or illegal for the fields they’re going into.

It wasn’t until I spent some time looking over the source data that I saw the problem: there is a duplicate key in the data.  This error is NiFi’s way of complaining about it.

In our case the underlying table doesn’t have good keys, or a good structure in general, and I’m planning to replace it soon anyway, but updating the primary keys to allow the duplicate data (because it IS valid data, despite the table design) has solved the issue.

NiFi Build Error

I’m testing NiFi out on my local Gentoo installation to prepare for an implementation at work, and after a rather lengthy build/test process (“ten minutes” my fanny) ran into this error:

$ mvn clean install
[INFO] Scanning for projects...
...
'Script Engine' validated against 'ECMAScript' is invalid because Given value not found in allowed set 'Groovy, lua, python, ruby'

This error left me scratching my head.  Nothing related to JavaScript/ECMAScript dependencies were mentioned anywhere.  How would you get it, anyway?  Webkit, I suppose…

Sudden epiphany: this is a new Gentoo installation, and this program, including the build script, is running Java.  Gentoo doesn’t install Sun Oracle’s Java by default, but instead comes with IcedTea out of the box.  It’s acceptable for some simple uses, but is buggy for any complex. (Minecraft is a great example where it just doesn’t work.)  I haven’t used Java for anything yet, so I hadn’t installed the JDK yet.  The build instructions specify JDK 1.7 or higher, but I didn’t think anything of it because I’m used to just having it installed.

echo "dev-java/oracle-jdk-bin Oracle-BCLA-JavaSE" \
  >> /etc/portage/package.license/file
emerge -av dev-java/oracle-jdk-bin
...
$ mvn clean install
[INFO] Scanning for projects...
...
[INFO] BUILD SUCCESS

Finally!

Bridging Wired and Wireless Networks, Gentoo-style

I want my wired and wireless networks to share a single 192.168.1.x address space (instead of separate 192.168.0.x and 192.168.1.x addresses).

In order to do that, we need to set up a bridge to merge disparate networks into a single space.

Part 1: The Basic Configuration

ADMtek NC100 (uses tulip driver)
Ralink RT61 PCI (uses rt61pci driver)
hostapd
linux 4.1.15-gentoo-r1
net-misc/bridge-utils 1.5
net-wireless/iw 3.17

Part 2: Making It Work

I started out creating a basic bridge, using the Gentoo Wiki as a guide:

cd /etc/init.d
ln -s net.lo net.br0

/etc/init.d/net.br0 start

There’s no need to change how hostapd starts; it still talks to wlan0 (not br0).

# /etc/conf.d/net

modules_wlan0="!iwconfig !wpa_supplicant"
config_wlan0="null"
config_eth0="null"
config_br0="192.168.1.1/24"
brctl_br0="setfd 0
sethello 10
stp off"
bridge_br0="eth0 wlan0"

The Problem

The above config is naive and doesn’t work right.  I got this error:

Can't add wlan0 to bridge br0: Operation not supported

Huh.  There’s nothing indicative in dmesg about the error, the last entry shows the bridge being created on the wired card and then being taken down.  Just to be sure, I created a bridge with just eth0 and it worked:

$ brctl show
bridge name   bridge id           STP enabled   interfaces
br0           8000.00045a42a698   no            eth0

After casting about a bit, I found a serverfault.com page that pointed to this fix:

$ iw dev wlan0 set 4addr on
$ brctl addif br0 wlan0

That works, but that won’t do me much good as a long-term solution.  I would need to pay a visit to the basement after every planned reboot and unplanned power outage, or else nobody can get onto the network.

( More about the 4addr option here. )

You can’t just add the option to modules_wlan0, it doesn’t work that way.  A quick visit back to the wiki suggested the solution, though, which is to define a preup function where we can execute arbitrary commands.

The Working Config

These statements are in addition to the WAN interface config:

# /etc/conf.d/net
modules_wlan0="!iwconfig !wpa_supplicant"
config_wlan0="null"
config_eth0="null"
config_br0="192.168.1.1/24"
brctl_br0="setfd 0
sethello 10
stp off"
bridge_br0="eth0 wlan0"

preup() {
    # br0 uses wlan0, and wlan0 needs to set the
    # 4addr option before being used on a bridge
    if echo "${IFACE}" | grep -q 'br0' ; then
        /usr/sbin/iw dev wlan0 set 4addr on
    fi

    return 0
}

Then do all the accounting to clean up:

rc-update add net.br0 default
rc-update del net.eth0 default
rc-update del net.wlan0 default

I also had to update my iptables config to refer to br0 instead of eth0 and wlan0.

Finally, a reboot to test that everything starts properly.

Setting up a Gentoo-Based Dual-Stack Router

Our network has been based around a home-built router for quite some time, ever since I got fed up with the crappy ActionTec router that Verizon bundled with our FiOS service. (If you’re going to offer high-speed internet, you should probably bundle equipment that can actually keep up.) I had originally followed a slightly older version of these instructions to get a nice basic router going. But I finally wanted better. I wanted the bright, shiny, new thing. I wanted IPv6.

So, here’s my instructions for going from an existing IPv4 router to dual-stack IPv4/6.

Note: I am using dnsmasq for DNS and DHCP, hostapd for wireless management, and an iptables firewall. Since Verizon still doesn’t widely support consumer IPv6, I’m using a tunnel broker to get my /6 address. If you’re using a different setup your mileage may vary. If you find anything that I appear to have forgotten, please let me know!

Step 1: Recompile the Kernel

This should be obvious: if you want to run ipv6 you need ipv6 support in your kernel. In order to trim as much off my kernel as possible I did not have it built in, and had to recompile.

You should also add netfilter support for ipv6 so that your firewall will work.

<br />
Networking support  ---&gt;<br />
    Networking options  ---&gt;<br />
        &lt;*&gt;   The IPv6 protocol  ---&gt;<br />
            &lt;*&gt;   IPv6: IPv6-in-IPv4 tunnel (SIT driver)<br />
        [*] Network packet filtering framework (Netfilter)  ---&gt;<br />
            IPv6: Netfilter Configuration  ---&gt;<br />
                &lt;M&gt; IPv6 NAT<br />
                &lt;M&gt; IP6 tables support (required for filtering)<br />
                &lt;M&gt;   Packet filtering<br />
                &lt;M&gt;   ip6tables NAT support<br />
                &lt;M&gt;     MASQUERADE target support<br />
                ... other filtering options as you may need for your situation<br />

Step 2: Update Your IPv6 Support

Again, it was never compiled in, in order to trim off unused bits of code. Add ‘ipv6’ to your USE variable and emerge --newuse world

Step 3: Install network tools (if they aren’t already)

emerge --noreplace sys-apps/iproute2 net-firewall/iptables

Step 4 (optional): Set up your tunnel

If your ISP doesn’t provide ipv6, and many don’t, you need to request an address range from a tunnel broker. I’m using Hurricane Electric, which is free, but there are others — see this list or just google it.

If you have multiple machines on your network (which is assumed, since this is a router guide), you may prefer a /48, so that autoconfig works nicely, instead of the default /64. This guide assumes a /48.

Going forward, replace 2001:470:891a: with your own /48 range.

Now activate your tunnel:

<br />
ip tunnel add he-ipv6 mode sit remote 1.2.3.4 local 5.6.7.8 ttl 255<br />
ip link set he-ipv6 up<br />
ip addr add 2001:470:1f06:2a3::2/64 dev he-ipv6<br />
ip route add ::/0 dev he-ipv6<br />
ip -f inet6 addr<br />

Step 5: Update Your Net Config

I have two wired and one wireless card in my router. Here’s what my /etc/conf.d/net looks like:

<br />
# enp2s0 is my exterior wired nic (aka public facing)<br />
# enp3s5 is my interior wired nic<br />
# wlp3s6 is my interior wireless nic</p>
<p>dhcp_enp2s0=&quot;nodns&quot; # we choose our own DNS, tyvm</p>
<p>config_enp3s5=&quot;192.168.0.1/24 2001:470:891a:0::/64&quot;</p>
<p>modules_wlp3s6=&quot;!iwconfig !wpa_supplicant&quot;<br />
config_wlp3s6=&quot;192.168.1.1/24 2001:470:891a:1::/48&quot;<br />
dns_servers_wlp3s6=&quot;127.0.0.1&quot;<br />

After making appropriate changes, restart your NICs. If you’re working remotely, you may want to be connected via two paths instead of just one (so when you inevitably get bounced and can’t reconnect, you still have a way back in).

A properly-configured set of addresses looks like this:

<br />
# ip addr<br />
1: lo: &amp;lt;LOOPBACK,UP,LOWER_UP&amp;gt; mtu 65536 qdisc noqueue state UNKNOWN group default<br />
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00<br />
    inet 127.0.0.1/8 brd 127.255.255.255 scope host lo<br />
       valid_lft forever preferred_lft forever<br />
    inet6 ::1/128 scope host<br />
       valid_lft forever preferred_lft forever<br />
2: enp2s0: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc pfifo_fast state UP group default qlen 1000<br />
    link/ether 00:e0:4d:bf:03:f5 brd ff:ff:ff:ff:ff:ff<br />
    inet 108.20.118.17/24 brd 108.20.118.255 scope global enp2s0<br />
       valid_lft forever preferred_lft forever<br />
    inet6 fe80::cbdf:25c0:c948:f4bb/64 scope link<br />
       valid_lft forever preferred_lft forever<br />
3: enp3s5: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000<br />
    link/ether 00:04:5a:42:a6:98 brd ff:ff:ff:ff:ff:ff<br />
    inet 192.168.0.1/24 brd 192.168.0.255 scope global enp3s5<br />
       valid_lft forever preferred_lft forever<br />
    inet6 2001:470:891a::/64 scope global<br />
       valid_lft forever preferred_lft forever<br />
    inet6 fe80::204:5aff:fe42:a698/64 scope link<br />
       valid_lft forever preferred_lft forever<br />
4: wlp3s6: &amp;lt;BROADCAST,MULTICAST,UP,LOWER_UP&amp;gt; mtu 1500 qdisc mq state UP group default qlen 1000<br />
    link/ether 00:1a:ef:07:4d:a7 brd ff:ff:ff:ff:ff:ff<br />
    inet 192.168.1.1/24 brd 192.168.1.255 scope global wlp3s6<br />
       valid_lft forever preferred_lft forever<br />
    inet6 2001:470:891a:1::/64 scope global<br />
       valid_lft forever preferred_lft forever<br />
    inet6 fe80::21a:efff:fe07:4da7/64 scope link<br />
       valid_lft forever preferred_lft forever<br />
5: sit0@NONE:  mtu 1480 qdisc noop state DOWN group default<br />
    link/sit 0.0.0.0 brd 0.0.0.0<br />
6: he-ipv6@NONE: &amp;lt;POINTOPOINT,NOARP,UP,LOWER_UP&amp;gt; mtu 1480 qdisc noqueue state UNKNOWN group default<br />
    link/sit 108.20.118.17 peer 209.51.161.14<br />
    inet6 2001:470:1f06:2a3::2/64 scope global<br />
       valid_lft forever preferred_lft forever<br />
    inet6 fe80::6c14:7611/64 scope link<br />
       valid_lft forever preferred_lft forever<br />

Test it with a ping:

ping6 www.kame.net

Step 6: Reconfigure dnsmasq

You’ll need to add router advertisments and your new addresses. Rather than hard-coding an address, dnsmasq offers a ‘constructor’ label which figures it out automatically. Here’s the relevant section from my /etc/dnsmasq.conf:

<br />
domain-needed<br />
bogus-priv<br />
domain=jonesling.us<br />
dhcp-authoritative<br />
enable-ra<br />
dhcp-range=192.168.0.20,192.168.0.100,12h<br />
dhcp-range=192.168.1.20,192.168.1.100,12h<br />
dhcp-range=192.168.2.20,192.168.2.100,12h<br />
dhcp-range=::,constructor:enp3s5,ra-names,slaac,12h<br />
dhcp-range=::,constructor:wlp3s6,ra-names,slaac,12h<br />
resolv-file=/etc/resolv.dnsmasq<br />
selfmx<br />
enable-ra<br />

And restart it: /etc/init.d/dnsmasq restart

Step 7: Configure your firewall

Pretty much every iptables reference in your firewall config will be mirrored with an ip6tables command.

Here’s my script to set up iptables (if you see an error or something stupid, I would appreciate your criticism – paired with your reasoning on why it should be changed so I can know better for next time).

<br />
#!/bin/bash<br />
# based on http://www.gentoo.org/doc/en/home-router-howto.xml</p>
<p># set to '0' to lock the kids out<br />
OPEN_INTERNET=1</p>
<p># these systems can get shut out when OPEN_INTERNET isn't true<br />
declare -a NO_SURFING=( 'wii-u'<br />
                        'kids-computer'<br />
                      )</p>
<p># these systems never get shut out<br />
declare -a OK_SURFING=( 'parents-computer'<br />
                        'parents-phone'<br />
                      )</p>
<p># these ports take precedence over CLOSED_PORTS<br />
declare -a OPEN_TCP_PORTS=( 'ssh'<br />
                            'http'<br />
                            'mail'<br />
                            'submission'<br />
                          )</p>
<p>declare -a OPEN_UDP_PORTS=( 'submission' )</p>
<p># if the port is meant to be closed, we close tcp *AND* udp<br />
declare -a CLOSED_PORTS=( '0:1055'<br />
                          'svn'<br />
                          'distcc'<br />
                          'x11'<br />
                          'nfs'<br />
                          'icpv2'<br />
                          'mysql'<br />
                          'rtsp'<br />
                          '3128' # squid<br />
                          '3130' # squid ICP<br />
                          '3551' # nisport<br />
                        )</p>
<p>declare -a LAN_SERVICES=( &quot;svn&quot; )</p>
<p># blacklisted IPs and ranges<br />
# http://www.iana.org/assignments/ipv4-address-space/ipv4-address-space.xhtml<br />
declare -a IP_BLACKLIST=( # APINIC<br />
                          # AFRINIC<br />
                          # LACNIC<br />
                          ...<br />
                        )</p>
<p>LAN=enp3s5<br />
WLAN=wlp3s6<br />
WAN=enp2s0<br />
SIT=he-ipv6</p>
<p>INSIDE=( $LAN $WLAN )</p>
<p>LOCAL_RANGE_IPV4='192.168.0.0/16'<br />
LOCAL_RANGE_IPV6='2001:470:891a::'</p>
<p># First we flush our current rules<br />
iptables -F<br />
iptables -t nat -F<br />
ip6tables -F<br />
ip6tables -t nat -F</p>
<p># Setup default policies to handle unmatched traffic<br />
iptables  -P INPUT ACCEPT<br />
iptables  -P OUTPUT ACCEPT<br />
iptables  -P FORWARD DROP<br />
ip6tables -P INPUT ACCEPT<br />
ip6tables -P OUTPUT ACCEPT<br />
ip6tables -P FORWARD DROP</p>
<p># Then we lock our services so they only work from the LAN<br />
iptables  -I INPUT 1 -i ${LAN}  -j ACCEPT<br />
iptables  -I INPUT 1 -i ${WLAN} -j ACCEPT<br />
iptables  -I INPUT 1 -i lo      -j ACCEPT<br />
ip6tables -I INPUT 1 -i ${LAN}  -j ACCEPT<br />
ip6tables -I INPUT 1 -i ${WLAN} -j ACCEPT<br />
ip6tables -I INPUT 1 -i lo      -j ACCEPT</p>
<p># block members of IP_BLACKLIST, plus any addresses passed in on the<br />
# command line<br />
for IP in ${IP_BLACKLIST[@]} ; do<br />
    iptables -I INPUT -s ${IP} -p TCP --dport ssh -j DROP<br />
done</p>
<p>for IP in $@; do<br />
    iptables -I INPUT -s ${IP} -d 0/0 -j REJECT<br />
done</p>
<p>iptables  -A INPUT -p UDP --dport bootps -i ${WAN} -j REJECT<br />
ip6tables -A INPUT -p UDP --dport bootps -i ${SIT} -j REJECT<br />
iptables  -A INPUT -p UDP --dport domain -i ${WAN} -j REJECT<br />
ip6tables -A INPUT -p UDP --dport domain -i ${SIT} -j REJECT</p>
<p># Explicitly allow access to services on the WAN<br />
for SERVICE in ${LAN_SERVICES[@]} ; do<br />
    for IFACE in ${INSIDE[@]} ; do<br />
        iptables  -A INPUT -p TCP --dport svn -i ${IFACE} -j ACCEPT<br />
        iptables  -A INPUT -p UDP --dport svn -i ${IFACE} -j ACCEPT<br />
        ip6tables -A INPUT -p TCP --dport svn -i ${IFACE} -j ACCEPT<br />
        ip6tables -A INPUT -p UDP --dport svn -i ${IFACE} -j ACCEPT<br />
    done<br />
done</p>
<p># Allow access to our server from the WAN<br />
for PORT in ${OPEN_TCP_PORTS[@]} ; do<br />
    iptables  -A INPUT -p TCP --dport $PORT -i ${WAN} -j ACCEPT<br />
    ip6tables -A INPUT -p TCP --dport $PORT -i ${SIT} -j ACCEPT<br />
done</p>
<p>for PORT in ${OPEN_UPD_PORTS[@]} ; do<br />
    iptables  -A INPUT -p UDP --dport PORT -i ${WAN} -j ACCEPT<br />
    ip6tables -A INPUT -p UDP --dport PORT -i ${SIT} -j ACCEPT<br />
done</p>
<p># Drop TCP / UDP packets to privileged ports<br />
for PORT in ${CLOSED_PORTS[@]} ; do<br />
    iptables  -A INPUT -p TCP -i ${WAN} -d 0/0 --dport ${PORT} -j DROP<br />
    ip6tables -A INPUT -p TCP -i ${SIT} -d 0/0 --dport ${PORT} -j DROP</p>
<p>    iptables  -A INPUT -p UDP -i ${WAN} -d 0/0 --dport ${PORT} -j DROP<br />
    ip6tables -A INPUT -p UDP -i ${SIT} -d 0/0 --dport ${PORT} -j DROP<br />
done</p>
<p>iptables  -I FORWARD -i ${LAN} -d $LOCAL_RANGE_IPV4 -j ACCEPT<br />
iptables  -A FORWARD -i ${LAN} -s $LOCAL_RANGE_IPV4 -j ACCEPT<br />
ip6tables -I FORWARD -i ${LAN} -d $LOCAL_RANGE_IPV6 -j ACCEPT<br />
ip6tables -A FORWARD -i ${LAN} -s $LOCAL_RANGE_IPV6 -j ACCEPT</p>
<p>if (( OPEN_INTERNET )); then<br />
    echo 'yay, everybody gets internet'<br />
    iptables  -I FORWARD -i ${WLAN} -d $LOCAL_RANGE_IPV4 -j ACCEPT<br />
    iptables  -A FORWARD -i ${WLAN} -s $LOCAL_RANGE_IPV4 -j ACCEPT<br />
    ip6tables -I FORWARD -i ${WLAN} -d $LOCAL_RANGE_IPV6 -j ACCEPT<br />
    ip6tables -A FORWARD -i ${WLAN} -s $LOCAL_RANGE_IPV6 -j ACCEPT<br />
else<br />
    echo &quot;boo, only ${OK_SURFING[@]} get internet&quot;<br />
    for IP in ${OK_SURFING[@]}; do<br />
        iptables -I FORWARD -i ${WLAN} -d $IP/255.255.255.255 -j ACCEPT<br />
        iptables -A FORWARD -i ${WLAN} -s $IP/255.255.255.255 -j ACCEPT<br />
    done<br />
fi</p>
<p>iptables  -A FORWARD -i ${WAN} -d $LOCAL_RANGE_IPV4 -j ACCEPT<br />
ip6tables -A FORWARD -i ${WAN} -d $LOCAL_RANGE_IPV6 -j ACCEPT</p>
<p>iptables  -t nat -A POSTROUTING -o ${WAN} -j MASQUERADE<br />
ip6tables -t nat -A POSTROUTING -o ${SIT} -j MASQUERADE</p>
<p># This is so when we boot we don't have to run the rules by hand<br />
/etc/init.d/iptables save<br />
/etc/init.d/ip6tables save</p>
<p># fail2ban should be reloaded after flushing iptables<br />
/etc/init.d/fail2ban reload<br />

Step 8: Update your DNS

Add a AAAA record to your domain’s DNS record.  You may have to keep this one up-to-date yourself.

Interesting to note: you might be thinking “crap, what’s the ipv6 equivalent of these CNAME records?”  Stop worrying, there isn’t.  The CNAME is read like normal, but ipv6 clients will then look up the AAAA (instead of the A) record of the destination host.  It just works.

What?  You built your own router but you don’t have your own domain?  WTF is wrong with you?

Step 9: Reboot your clients

While I was working, I made a bunch of mistakes and my clients had multiple ipv6 addresses – making networking from them unstable as they didn’t necessarily know which address to use. Rebooting will clear them – and make sure your config is proper.

At this point your clients should be in ipv6 and you’re gonna be all excited to see if work.  Browsers take ipv6 addresses a little differently: http://[2001:470:1f06:2a3::2]/

IPv6

If you’re white and nerdy, like me, you know that your small victories aren’t like other peoples’ small victories.  Today’s small victory is IPv6.

I has it.

At this very moment, this blog can be served to you, or may already be served to you, over IPv6 if you have it too.

Setting it up on your home-built router isn’t straight-forward, especially if your ISP doesn’t offer IPv6 – you have to find a tunnel broker.  (I’m using Hurricane Electric, which provides free /64 and /48 tunnels.)  Clients seem to work fairly automatically.  Have fun figuring out all the little things you need to tweak on your router, though.

Things to note:

  • hostapd seems to knock off the IPv6 address of your wireless NIC when you start it – you need to re-add the address by hand, like this:
    ifconfig wlp3s6 inet6 add 2001:470:891a::/48
  • dnsmasq has a special tag to automatically read addresses from devices, called ‘constructor’, which is easier than copying your dynamic tunnel everywhere:
    dhcp-range=::,constructor:wlp3s6,ra-names,slaac,12h
  • You may use the IPv6 equivalent of ‘private’ IP addresses, but you don’t need to anymore.
  • dyn.com hides their non-typical DNS record types, and you have to enable the ‘expert interface’ to see AAAA and other record types, but otherwise there’s no difference in setting up dynamic host addressing.
    • One quirk that may not be immediately obvious: You don’t need to have separate IPv6 CNAME records.  An IPv6 client will check the CNAME, pull the destination hostname, then pull the AAAA record.
  • Most network tools have IPv6 equivalents – ping doesn’t work with IPv6 addresses, but ping6 does.
  • There’s a special format for using an IPv6 address in a web browser: http://[2001:470:1f06:2a3::2]/ if you go direct to the blog’s ipv6 address today.

But besides all that, it really works!

$ ping6 -c1 jonesling.us
PING jonesling.us(quinnjones-2-pt.tunnel.tserv4.nyc4.ipv6.he.net) 56 data bytes
64 bytes from quinnjones-2-pt.tunnel.tserv4.nyc4.ipv6.he.net: icmp_seq=1 ttl=64 time=0.508 ms

--- jonesling.us ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.508/0.508/0.508/0.000 ms

Airprint woes

It’s all my fault, really.  This wouldn’t have been an issue if I had just let Xtina use my computer to print her boarding pass, but in my defense I didn’t know that she was doing that.  So I gave her our iPad to use.

When it came time to print, she quite logically asked me how she would do that.  I, of course, did not know how — I’ve never tried printing from iPad or smartphone, though I vaguely knew it was possible.  The issue just never came up and I hate printers.

I knew that it would require avahi, so I started installing that on our printserver while I hit Google to see what else I would need.

The first hit was a very fine article by Linux Magazine, and it explained pretty much everything.  But it’s never that simple, because nothing printed and cups started using 100% of a CPU.

Repeated in the /var/log/cups/error_log a billion times were messages like these:

Request from "192.168.1.32" using invalid Host: field "dandelion.local:631"

That took a little more detective work because I didn’t read the Linux Magazine article carefully enough.  The solution was to add an additional directive to the cups config:

--- /backup/snapshots/dandelion.0/etc/cups/cupsd.conf   2015-06-08 08:33:31.000000000 -0400
+++ /etc/cups/cupsd.conf        2015-06-24 19:29:34.410488191 -0400
@@ -1,6 +1,7 @@
 LogLevel warn
 PageLogFormat
 # Allow remote access
+ServerAlias *
 Port 631
 Listen /run/cups/cups.sock
 # Share local printers on the local network.

Summary:

Gentoo packages required:

  • net-print/cups
  • net-dns/avahi

Also download and run airprint-generate after cups is configured and running.

If you have iOS 6+, which is pretty much a given nowadays, make sure you have the correct MIME types available, and add them if not:

echo 'image/urf urf string(0,UNIRAST<00>)' > \
    /usr/share/cups/mime/airprint.types
echo 'image/urf application/pdf 100 pdftoraster' > \
    /usr/share/cups/mime/airprint.convs

Add the appropriate services to your default runlevel, and start them as well:

# rc-update add cupsd default
# rc-update add cups-browsed default
# rc-update add avahi-daemon default