So I am lucky enough to have AT&T gigabit fiber at my home. The installer was able to run the fiber into my garage and mount the transceiver with the rest of my networking equipment. The connection is stable and fast, but one thing always bothered me, the gateway/router box. It has a hardcoded DNS server that was simply unacceptable, so I ran a pfSense box through the gateway’s DMZplus feature. With that I lost IPv6 and still have the problem of going through the AT&T gateway that some have shown to have security vulnerabilities.
After a bit of research I found a somewhat complete article, Bypassing Gigapower’s Provided "Modem", that got me going in the right direction. I put everything in netctl config files so everything would be automated. Here is a diagram of the setup:
+--------------+ +--------------+
| AT&T | | AT&T |
| Transceiver +----+ +--+ Gateway |
+--------------+ | | +--------------+
| |
+--------------+
| | Linux | | 0 = eth0
| | | | 1 = eth1
| 0 1 2 | 2 = eth2
+--------------+
|
+--------------+LAN
With this config, we are setting up a bridge (br0) between eth0 and eth2 and adding a vlan 0 interface on the bridge (br0.0) with a spoofed address of the AT&T Gateway’s MAC address.
For the connection to the AT&T Gateway we create /etc/netctl/gateway-profile. eth2 is my interface that goes to the AT&T Gateway.
Description='ATT Gatetay Interface'
Interface=eth2
Connection=ethernet
ForceConnect=yes
IP=no
For the connection to the AT&T Transceiver we create /etc/netctl/ont-profile. eth0 is my interface that goes to the AT&T Transceiver.
Description='ONT Interface'
Interface=eth0
Connection=ethernet
ForceConnect=yes
IP=no
For our connection to the LAN we create /etc/netctl/internal-profile and set static addresses. The IPv6 Address6 comes from our allocation. eth1 is my interface that goes to my LAN switch.
Description='Internal Interface'
Interface=eth1
Connection=ethernet
IP='static'
Address=('192.168.1.0/24')
IP6=static
Address6=('1234:aaaa:aaaa:aaaa::1/64')
The bridge between the AT&T Gateway and the AT&T Transceiver is created next with /etc/netctl/bridge.
Description="Bridge ONT to Gateway"
Interface=br0
Connection=bridge
BindsToInterfaces=('eth0' 'eth2')
IP=no
SkipForwardingDelay=yes
Netctl has a feature to run a script after the interface is up by creating /etc/netctl/interfaces/br0, and that is where we will adjust the bridge to pass the 802.1X traffic which is normally not forwarded by bridges.
#!/usr/bin/env bash
/usr/bin/echo -n 8 > /sys/class/net/br0/bridge/group_fwd_mask
We need a way to route traffic through the bridge and look as if we are coming from the AT&T Gateway. We do that by creating a VLAN 0 interface off of the bridge with /etc/netctl/vlan-bridge. The address and gateway IP addresses are copied from the AT&T Gateway.
Description="Spoofed address of modem"
Interface=br0.0
BindsToInterfaces=br0
Connection=vlan
VLANID=0
IP=static
Address="123.123.123.4/22"
Gateway="123.123.123.1"
DNS=("127.0.0.1")
To get the spoofed MAC address we create /etc/netctl/interfaces/br0.0 and put in the MAC address of the AT&T Gateway’s outside interface.
#!/usr/bin/env bash
macchanger -m 11:22:33:44:55:66 br0.0
I use IPv6 and to get that setup I copied the values from the AT&T Gateway 6RD config and created /etc/netctl/tunnel6rd. These values can be found on the AT&T gateway device.
Description='ATT 6RD IPv6'
Interface=6rdtun
Connection=tunnel
Local='123.123.123.4'
Mode='sit'
Remote='any'
IPCustom='tunnel 6rd dev 6rdtun 6rd-prefix 1234:aaaa::/28'
IP6='static'
Address6='1234:aaaa:aaaa:aaaa::1/60'
Routes6=('1234::/3 via ::12.83.49.81')
We really need to stop any traffic other then 802.1X from getting to the AT&T Gateway, so we use ebtables to block the traffic with /etc/netctl/interfaces/eth2. eth2 is the interface that goes to the AT&T Gateway.
#!/usr/bin/env bash
ebtables -t filter -A FORWARD -i eth2 -p 802_1Q --vlan-encap 0x888e -j ACCEPT
ebtables -t filter -A FORWARD -i eth2 -p 802_1Q -j DROP
ebtables -t filter -A FORWARD -o eth2 -p 802_1Q --vlan-encap 0x888e -j ACCEPT
ebtables -t filter -A FORWARD -o eth2 -p 802_1Q -j DROP
We will need the firewall to provide forwarding and some basic filtering. Below is an example of such firewall rules.
#/etc/iptables/iptables.rules
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -o br0.0 -j MASQUERADE
COMMIT
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
# basic global accept rules - ICMP, loopback, traceroute, established all accepted
-A INPUT -s 127.0.0.0/8 -d 127.0.0.0/8 -i lo -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -m state --state ESTABLISHED -j ACCEPT
# enable traceroute rejections to get sent out
-A INPUT -p udp -m udp --dport 33434:33523 -j REJECT --reject-with icmp-port-unreachable
-A INPUT -i eth1 -j ACCEPT
#uPNP
-A INPUT -i eth1 -p tcp --dport 33671 -j ACCEPT
-A INPUT -i eth1 -p udp --dport 5351 -j ACCEPT
-A INPUT -i eth1 -p udp --dport 1900 -j ACCEPT
# DNS - accept from LAN
-A INPUT -i eth1 -p tcp --dport 53 -j ACCEPT
-A INPUT -i eth1 -p udp --dport 53 -j ACCEPT
# SSH - accept from LAN
-A INPUT -i eth1 -p tcp --dport 22 -j ACCEPT
# DHCP client requests - accept from LAN
-A INPUT -i eth1 -p udp --dport 67:68 -j ACCEPT
# Forwarding rules
-A FORWARD -p all -i br0 -j ACCEPT
# forward packets along established/related connections
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# forward from LAN (eth1) to WAN (br0.0)
-A FORWARD -i eth1 -o br0.0 -j ACCEPT
-A FORWARD -i eth0 -j ACCEPT
-A FORWARD -i eth1 -j ACCEPT
-A FORWARD -i br0.0 -j ACCEPT
-A FORWARD -i br0 -j ACCEPT
COMMIT
#/etc/iptables/ip6tables.rules
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [24:3686]
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth1 -j ACCEPT
-A INPUT -i 6rdtun -m state --state RELATED,ESTABLISHED -j ACCEPT
#ICMPv6
-A INPUT -i 6rdtun -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT
-A INPUT -i 6rdtun -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT
-A INPUT -i 6rdtun -p icmpv6 --icmpv6-type time-exceeded -j ACCEPT
-A INPUT -i 6rdtun -p icmpv6 --icmpv6-type parameter-problem -j ACCEPT
-A INPUT -i 6rdtun -p icmpv6 --icmpv6-type echo-request -m limit --limit 900/min -j ACCEPT
-A INPUT -i 6rdtun -p icmpv6 --icmpv6-type echo-reply -m limit --limit 900/min -j ACCEPT
-A INPUT -i 6rdtun -p icmpv6 --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT
-A INPUT -i 6rdtun -p icmpv6 --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j ACCEPT
-A INPUT -i 6rdtun -p icmpv6 --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j ACCEPT
-A INPUT -i 6rdtun -p icmpv6 --icmpv6-type redirect -m hl --hl-eq 255 -j ACCEPT
#
-A INPUT -i 6rdtun -j DROP
-A FORWARD -i eth1 -j ACCEPT
-A FORWARD -i 6rdtun -m state --state RELATED,ESTABLISHED -j ACCEPT
#ICMPv6
-A FORWARD -i 6rdtun -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT
-A FORWARD -i 6rdtun -p icmpv6 --icmpv6-type packet-too-big -j ACCEPT
-A FORWARD -i 6rdtun -p icmpv6 --icmpv6-type time-exceeded -j ACCEPT
-A FORWARD -i 6rdtun -p icmpv6 --icmpv6-type parameter-problem -j ACCEPT
-A FORWARD -i 6rdtun -p icmpv6 --icmpv6-type echo-request -m limit --limit 900/min -j ACCEPT
-A FORWARD -i 6rdtun -p icmpv6 --icmpv6-type echo-reply -m limit --limit 900/min -j ACCEPT
-A FORWARD -i 6rdtun -p icmpv6 --icmpv6-type router-advertisement -m hl --hl-eq 255 -j ACCEPT
-A FORWARD -i 6rdtun -p icmpv6 --icmpv6-type neighbor-solicitation -m hl --hl-eq 255 -j ACCEPT
-A FORWARD -i 6rdtun -p icmpv6 --icmpv6-type neighbor-advertisement -m hl --hl-eq 255 -j ACCEPT
-A FORWARD -i 6rdtun -p icmpv6 --icmpv6-type redirect -m hl --hl-eq 255 -j ACCEPT
-A FORWARD -i 6rdtun -j DROP
COMMIT
Now we just need to get everything to start.
netctl enable internal-profile
netctl enable ont-profile
netctl enable bridge
netctl enable tunnel6rd
netctl enable vlan-bridge
netctl enable gateway-profile
systemctl enable iptables