Home Assistants HACS and IPv6 issues

Home Assistant (HA) has a fantastic extension ecosystem that uses the Home Assistant Community Store (HACS). Most of the repositories are held on Github that have specific files copied down to your HA instance. Attempting to install a new front-end card (button-card) I kept getting a timeout issue, this seemed odd, so I SSH’d into the VM that has the container, and then exec’d into the container with:

docker exec -it <container name> bash

to install the module manually. Using wget I saw that it was attempting to connect via IPv6, and failing. I knew that my network was working with IPv6 routing as most other services function over IPv6. And that is where I came across this discussion: IPv6 support for cloning Git repositories · community · Discussion #10539 (github.com)

It appeared that my solution was going to be that I needed to disable IPv6, or at the very least prevent the container from resolving an IPv6 address for Github and associated domains. I could not disable IPv6 across the network as that would impact Thread, and other network enabled systems. I needed to prevent my local DNS from resolving the specific domains, and only returning the IPv4 entries.

My router is running OpnSense, and it has the DNS service of Unbound DNS. Initially I attempted to use the GUI to block the IPv6, but it was not granular enough. I came across this forum: Netflix and HE.net tunnel fixed using Unbound python module | Netgate Forum that lead me to this Github Gist: Unbound python-script to route websites over IPv4. (github.com)

/var/unbound/no-aaaa.py
def init(id, cfg):
    return True

def deinit(id):
    return True

def inform_super(id, qstate, superqstate, qdata):
    return True

domains = [
    ".github.com.",
    ".github.io",
    ".githubusercontent.com"
]

def operate(id, event, qstate, qdata):
    if event == MODULE_EVENT_NEW or event == MODULE_EVENT_PASS:
        if qstate.qinfo.qtype != RR_TYPE_AAAA:
            qstate.ext_state[id] = MODULE_WAIT_MODULE
            return True

        for domain in domains:
            if qstate.qinfo.qname_str == domain or qstate.qinfo.qname_str.endswith("." + domain):
                msg = DNSMessage(qstate.qinfo.qname_str, RR_TYPE_A, RR_CLASS_IN, PKT_QR | PKT_RA | PKT_AA)
                if not msg.set_return_msg(qstate):
                    qstate.ext_state[id] = MODULE_ERROR
                    return True
                # We don't need validation, result is valid
                qstate.return_msg.rep.security = 2
                qstate.return_rcode = RCODE_NOERROR
                qstate.ext_state[id] = MODULE_FINISHED
                log_info("no-aaaa: blocking AAAA request for %s" % qstate.qinfo.qname_str)
                return True

        qstate.ext_state[id] = MODULE_WAIT_MODULE
        return True

    if event == MODULE_EVENT_MODDONE:
        qstate.ext_state[id] = MODULE_FINISHED
        return True

    qstate.ext_state[id] = MODULE_ERROR
    return True

log_info("pythonmod: script loaded")
Python

And then adding the following line to the /var/unbound/unbound.conf

python-script: /var/unbound/no-aaaa.py

Then restarting the Unbound DNS service in the OpnSense UI, restarting the VM, and attempting again allowed me to install the HACS component that I wanted. At some point in the future I will unwind this to see if it has been rectified, but for the moment it is working.