bin | ||
img | ||
README.md |
About
This repository includes my notes on enabling a true bridge mode setup with AT&T U-Verse and pfSense. This method utilizes netgraph which is a graph based kernel networking subsystem of FreeBSD. This low-level solution was required to account for the unique issues surrounding bridging 802.1X traffic and tagging a VLAN with an id of 0. I've tested and confirmed this setup works with AT&T U-Verse Internet on the ARRIS NVG589 and BGW210-700 residential gateways (probably others too).
There are a few other methods to accomplish true bridge mode, so be sure to see what easiest for you. True Bridge Mode is also possible in a Linux via ebtables or using hardware with a VLAN swap trick. For me, I was not using a Linux-based router and the VLAN swap did not seem to work for me.
While many AT&T residential gateways offer something called IP Passthrough, it does not provide the same advantages of a true bridge mode. For example, the NAT table is still managed by the gateway, which is limited to a measily 8192 sessions (although it becomes unstable at even 60% capacity).
The netgraph method will allow you to fully utilize your own router and fully bypass your residential gateway. It survives reboots, re-authentications, IPv6, and new DHCP leases.
How it Works
Before continuing to the setup, it's important to understand how this method works. This will make configuration and troubleshooting much easier.
Standard Procedue
First, let's talk about what happens in the standard setup (without any bypass). At a high level, the following process happens when the gateway boots up:
- All traffic on the ONT is protected with 802.1/X. So in order to talk to anything, the Router Gateway must first perform the authentication procedure. This process uses a unique ceritificate that is hardcoded on your residential gateway.
- Once the authentication completes, you'll be to properly "talk" to the outside. But strangely, all of your traffic will need to be tagged with VLAN id 0 before the IP gateway will respond. I believe VLAN0 is an obscure Cisco feature of 802.1Q CoS, but I'm not really sure.
- Once traffic is tagged with VLAN0, your residential gateway needs to request a public IPv4 address via DHCP. The MAC address in the DHCP request needs to match that of the MAC address that's assigned to your AT&T account. Other than that, there's nothing special about the DCHPv4 handshake.
- After the DHCP lease is issued, the WAN setup is complete. Your LAN traffic is then NAT'd and routed to the outside.
Bypass Procedure
To bypass the gateway using pfSense, we can emulate the standard procedure. If we connect our Residential Gateway and ONT to our pfSense box, we can brigde the 802.1/X authentication sequence, tag our WAN traffic as VLAN0, and request a public IPv4 via DHCP using a spoofed MAC address.
Unfortunately, there are some challenges with emulating this proccess. First, it's against RFC to bridge 802.1/X traffic and it is not supported. Second, tagging traffic as VLAN0 is not supported through the standard interfaces.
This is where netgraph comes in. Netgraph allows you to break some rules and build the proper plumbing to make this work. So, our cabling looks like this:
Residential Gateway
[ONT Port]
|
|
[nic0] pfSense [nic1]
|
|
[ONT]
Outside
With netgraph, our procedure looks like this (at a high level):
- The Residential Gateway initates a 802.1/X EAPOL-START.
- The packet then is bridged through netgraph to the ONT interface.
- If the packet matches an 802.1/X type (which is does), it is passed to the ONT interface. If it does not, the packet is discarded. This prevents our Residential Gateway from initiating DHCP. We want pfSense to handle that.
- The ONT should then see and respond to the EAPOL-START, which is passed back through our netgraph back to the residential gateway. At this point, the 802.1/X authentication should be complete.
- netgraph has also created an interface for us called
ngeth0
. This interface is connected tong_vlan
which is configured to tag all traffic as VLAN0 before sending it on to the ONT interface. - pfSense can then be configured to use
ngeth0
as the WAN interface. - Next, we spoof the MAC address of the residential gateway and request a DHCP lease on
ngeth0
. The packets get tagged as VLAN0 and exit to the ONT. - Now the DHCP handshake should complete and we should be on our way!
Hopefully, that now gives you an idea of what we are trying to accomplish. See the comments and commands bin/pfatt.sh
for details about the netgraph setup.
But enough talk. Now for the fun part!
Setup
Prerequisites
- At least three physical network interfaces on your pfSense server
- The MAC address of your Residential Gateway
- Local or console access to pfSense
- pfSense 2.4.3 (confirmed working, other versions should work but YMMV)
If you only have two NICs, you can buy this cheap USB NIC one from Amazon as your third. I've confirmed it works in my setup. It is compatible with FreeBSD 11.1 and I didn't have to install anything to get it working. Also, don't worry about the poor performance of USB NICs. This third NIC will only send/recieve a few packets periodicaly to authenticate your Router Gateway. The rest of your traffic will utilize your other (and much faster) NICs.
Install
-
Copy the
bin/ng_etf.ko
kernel module to/boot/kernel
on your pfSense box (because it isn't included):a) Use the pre-compiled kernel module from me, a random internet stranger:
scp bin/ng_etf.ko root@pfsense:/boot/kernel/ ssh root@pfsense chmod 555 /boot/kernel/ng_etf.ko
b) Or you, a responsible sysadmin, can compile the module yourself from another, trusted FreeBSD machine. You cannot build packages directly on pfSense. Your FreeBSD version should match that of your pfSense version. (Example: pfSense 2.4.3 = FreeBSD 11.1)
# from a FreeBSD machine (not pfSense!) fetch ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/amd64/11.1-RELEASE/src.txz tar -C / -zxvf src.txz cd /usr/src/sys/modules/netgraph make scp etf/ng_etf.ko root@pfsense:/boot/kernel/ ssh root@pfsense chmod 555 /boot/kernel/ng_etf.ko
-
Edit the following configuration variables in
bin/pfatt.sh
as noted below.$RG_ETHER_ADDR
should match the MAC address of your Residential Gateway. AT&T will only grant a DHCP lease to the MAC they assigned your device. In my environment, it's:ONT_IF='bce0' # NIC -> ONT / Outside RG_IF='ue0' # NIC -> Residential Gateway's ONT port RG_ETHER_ADDR='xx:xx:xx:xx:xx:xx' # MAC address of Residential Gateway
-
Copy
bin/pfatt.sh
to/usr/local/etc/rc.d
to enable it to run at boot:scp bin/pfatt.sh root@pfsense:/usr/local/etc/rc.d/ ssh root@pfsense chmod +x /usr/local/etc/rc.d/pfatt.sh
-
Connect cables:
$RG_IF
to Residiential Gateway on the ONT port (not the LAN ports!)$ONT_IF
to ONT (outside)LAN NIC
to local switch (as normal)
-
Prepare for console access.
-
Reboot.
-
pfSense will detect new interfaces on bootup. Follow the prompts on the console to configure
ngeth0
as your pfSense WAN. Your LAN interface should not change. pfSense does not need to manage$RG_IF
or$ONT_IF
. I would advise not enabling those interfaces in pfSense as it can cause problems with the netgraph. -
In the webConfigurator, configure the WAN interface (
ngeth0
) to DHCP using the MAC address of your Residential Gateway.
If everything is setup correctly, netgraph should be bridging EAP traffic between the ONT and RG, tagging the WAN traffic with VLAN0, and your WAN interface configured with an IPv4 address via DHCP.
IPv6 Setup
Once your netgraph setup is in place and working, there aren't any netgraph changes required to the setup to get IPv6 working. These instructions can also be followed with a different bypass method other than the netgraph method. Big thanks to @pyrodex1980's post on DSLReports for sharing your notes.
This setup assumes you have a fairly recent version of pfSense. I'm using 2.4.3.
DUID Setup
- Go to System > Advanced > Networking
- Configure DHCP6 DUID to DUID-EN
- Configure DUID-EN to 3561
- Configure your IANA Private Enterprise Number. This number is unique for each customer and (I believe) based off your Residential Gateway serial number. I grabbed mine off a pcap of the Residential Gateway. Fire up Wireshark and look for the value in DHCPv6 > Client Identifier > Identifier. Add the value as colon separated hex values
00:00:00
. - Save
WAN Setup
- Go to Interfaces > WAN
- Enable IPv6 Configuration Type as DHCP6
- Scroll to DCHP6 Client Configuration
- Enable Advanced Configuration
- Enable Configuration Override
- Enable Debug
- Enable Do not wait for a RA
- Configure Configuration File to
/cf/conf/att_dhcp6.conf
- Save
Configuration File
- Logon to your pfsense box and add the following file to
/cf/conf/att_dhcp6.conf
changing the WAN / LAN interface names to match your setup:
# WAN
interface ngeth0 {
send ia-na 1; # request stateful address
send ia-pd 1; # request prefix delegation - LAN
request domain-name-servers;
};
id-assoc na 1 { };
id-assoc pd 1 {
prefix ::/60 infinity;
# LAN
prefix-interface bce1 {
sla-id 0;
sla-len 4;
};
};
LAN Setup
- Go to Interfaces > LAN
- Change the IPv6 Configuration Type to Track Interface
- Under Track IPv6 Interface, assign IPv6 Interface to your WAN interface.
- Configure IPv6 Prefix ID to 0
- Save
DHCPv6 Server & RA
- Go to Services > DHCPv6 Server & RA
- Enable DHCPv6 server on interface LAN
- Configure a range of ::1000 to ::2000
- Configure a Prefix Delegation Range to 64
- Add a few IPv6 DNS servers
- Save
- Go to the Router Advertisements tab
- Configure Router mode as Stateless DHCP
- Save
That's it! Now your clients should be recieving public IPv6 addresses via DHCP6.
Troubleshooting
tcpdump
Use tcpdump to watch the authentication, vlan and dhcp bypass process (see above). Run tcpdumps on the $ONT_IF
interface and the $RG_IF
interface:
tcpdump -ei $ONT_IF
tcpdump -ei $RG_IF
Restart your Residential Gateway. From the $RG_IF
interface, you should see some EAPOL starts like this:
MAC (oui Unknown) > MAC (oui Unknown), ethertype EAPOL (0x888e), length 60: POL start
If you don't see these, make sure you're connected to the ONT port.
These packets come every so often. I think the RG does some backoff / delay if doesn't immediately auth correctly. You can always reboot your RG to initiate the authentication again.
If your netgraph is setup correctly, the EAP start packet from the $RG_IF
will be bridged onto your $ONT_IF
interface. Then you should see some more EAP packets from the $ONT_IF
interface and $RG_IF
interface as they negotiate 802.1/X EAP authentication.
Once that completes, watch $ONT_IF
and ngeth0
for DHCP traffic.
tcpdump -ei $ONT_IF port 67 or port 68
tcpdump -ei ngeth0 port 67 or port 68
Verify you are seeing 802.1Q (tagged as vlan0) traffic on your $ONT_IF
interface and untagged traffic on ngeth0
.
Verify the DHCP request is firing using the MAC address of your Residential Gateway.
If the VLAN0 traffic is being properly handled, next pfSense will need to request an IP. ngeth0
needs to DHCP using the authorized MAC address. You should see an untagged DCHP request on ngeth0
carry over to the $ONT_IF
interface tagged as VLAN0. Then you should get a DHCP response and you're in business.
If you don't see traffic being bridged between ngeth0
and $ONT_IF
, then netgraph is not setup correctly.
Promiscuous Mode
pfatt.sh
will put $RG_IF
in promiscuous mode via /sbin/ifconfig $RG_IF promisc
. Otherwise, the EAP packets would not bridge. I think this is necessary for everyone but I'm not sure. Turn it off if it's casuing issues.
netgraph
The netgraph system provides a uniform and modular system for the implementation of kernel objects which perform various networking functions. If you're unfamilar with netgraph, this tutorial is a great introduction.
Your netgraph should look something like this:
In this setup, the ue0
interface is my $RG_IF
and the bce0
interface is my $ONT_IF
. You can generate your own graphviz via ngctl dot
. Copy the output and paste it at webgraphviz.com.
Try these commands to inspect whether netgraph is configured properly.
-
Confirm kernel modules are loaded with
kldstat -v
. The following modules are required:- netgraph
- ng_ether
- ng_eiface
- ng_one2many
- ng_vlan
- ng_etf
-
Issue
ngctl list
to list netgraph nodes. Inspectpfatt.sh
to verify the netgraph output matches the configuration in the script. It should look similar to this:
$ ngctl list
There are 9 total nodes:
Name: o2m Type: one2many ID: 000000a0 Num hooks: 3
Name: vlan0 Type: vlan ID: 000000a3 Num hooks: 2
Name: ngeth0 Type: eiface ID: 000000a6 Num hooks: 1
Name: <unnamed> Type: socket ID: 00000006 Num hooks: 0
Name: ngctl28740 Type: socket ID: 000000ca Num hooks: 0
Name: waneapfilter Type: etf ID: 000000aa Num hooks: 2
Name: laneapfilter Type: etf ID: 000000ae Num hooks: 3
Name: bce0 Type: ether ID: 0000006e Num hooks: 1
Name: ue0 Type: ether ID: 00000016 Num hooks: 2
- Inspect the various nodes and hooks. Example for
ue0
:
$ ngctl show ue0:
Name: ue0 Type: ether ID: 00000016 Num hooks: 2
Local hook Peer name Peer type Peer ID Peer hook
---------- --------- --------- ------- ---------
upper laneapfilter etf 000000ae nomatch
lower laneapfilter etf 000000ae downstream
Reset netgraph
pfatt.sh
expects a clean netgraph before it can be ran. To reset a broken netgraph state, try this:
/usr/sbin/ngctl shutdown waneapfilter:
/usr/sbin/ngctl shutdown laneapfilter:
/usr/sbin/ngctl shutdown $ONT_IF:
/usr/sbin/ngctl shutdown $RG_IF:
/usr/sbin/ngctl shutdown o2m:
/usr/sbin/ngctl shutdown vlan0:
/usr/sbin/ngctl shutdown ngeth0:
pfSense
In some circumstances, pfSense may alter your netgraph. This is especially true if pfSense manages either your $RG_IF
or $ONT_IF
. If you make some interface changes and your connection breaks, check to see if your netgraph was changed.
Virtualization Notes
This setup has been tested on physical servers and virtual machines. Virtualization adds another layer of complexity for this setup, and will take extra consideration.
QEMU / KVM / Proxmox
Proxmox uses a bridged networking model, and thus utilizes Linux's native bridge capability. To use this netgraph method, you do a PCI passthrough for the $RG_IF
and $ONT_IF
NICs. The bypass procedure should then be the same.
You can also solve the EAP/802.1X and VLAN0/802.1Q problem by setting the group_fwd_mask
and creating a vlan0 interface to bridge to your VM. See Other Methods below.
ESXi
I haven't tried to do this with ESXi. Feel free to submit a PR with notes on your experience. PCI passthrough is probably the best approach here though.
Other Methods
Linux
If you're looking how to do this on a Linux-based router, please refer to this method which utilizes ebtables and some kernel features. The method is well-documented there and I won't try to duplicate it. This method is generally more straight forward than doing this on BSD. However, please submit a PR for any additional notes for running on Linux routers.
VLAN Swap
There is a whole thread on this at DSLreports. The gist of this method is that you connect your ONT, RG and WAN to a switch. Create two VLANs. Assign the ONT and RG to VLAN1 and the WAN to VLAN2. Let the RG authenticate, then change the ONT VLAN to VLAN2. The WAN the DHCPs and your in business.
However, I don't think this works for everyone. I had to explicity tag my WAN traffic to VLAN0 which wasn't supported on my switch.
OPNSense / FreeBSD
I haven't tried this with OPNSense or native FreeBSD, but I imagine the process is utlimately the same with netgraph. Feel free to submit a PR with notes on your experience.
U-verse TV
TODO
References
- http://blog.0xpebbles.org/Bypassing-At-t-U-verse-hardware-NAT-table-limits
- https://forum.netgate.com/topic/99190/att-uverse-rg-bypass-0-2-btc/
- http://www.dslreports.com/forum/r29903721-AT-T-Residential-Gateway-Bypass-True-bridge-mode
- https://www.dslreports.com/forum/r32127305-True-Bridge-mode-on-pfSense-with-netgraph
- https://www.dslreports.com/forum/r32116977-AT-T-Fiber-RG-Bypass-pfSense-IPv6
- http://www.netbsd.org/gallery/presentations/ast/2012_AsiaBSDCon/Tutorial_NETGRAPH.pdf
Credits
This took a lot of testing and a lot of hours to figure out. A unique solution was required for this to work in pfSense. If this helped you out, please buy us a coffee.