Linux: Bridging two ethernet connections together to allow second host onto first network

bridgelinuxnetworkingufw

Situation:

Network A <-> Server <-> Client Host

I want to allow the client host to access network A via a bridge, allowing both hosts access to network A over one ethernet connection.

These are all physical devices, and I'm using Linux/Ubuntu machines.

So I created a bridge, ntlbridge0 and enslaved two of the ethernet devices on the Server to it, eth0 (to network A) and eth1 (to the client).

Both the Server and the Client are getting their IP addresses via DHCP.
(which are assigned by Mac address by the router)

How am I supposed to set this connection up so that the Client can acquire a DHCP lease from the network?

While the client is trying to connect, it doesn't have an IP address yet, so I'm not sure how I can make a firewall rule to allow traffic from eth1 to eth0 without giving ufw/iptables an IP address to masquerade or forward to.

Ideally, I would like for both the Server and the Client to appear visible to network A at the same level. (Each should have their own IP, so network manager's 'Share Internet' won't work.) And the Client's MAC address should be visible to the network (so that it gets the correct IP from the router.

I had this working earlier (by means of which I am now unsure of), but now I can no longer get it to work even after I disable firewalls and re-create connections.

More details:

  • Using network-manager for all devices mentioned
  • UFW should stay enabled on both hosts for security
  • I'm using a patch cable between the server and client (does this still matter?)
  • All Server connections are working fine, and Client connects correctly when not being bridged through the server.

On the server:

route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         192.168.10.1    0.0.0.0         UG    426    0        0 ntlbridge0
192.168.10.0    *               255.255.255.0   U     425    0        0 ntlbridge0
192.168.10.0    *               255.255.255.0   U     426    0        0 ntlbridge0

nmcli dev status
DEVICE      TYPE      STATE      CONNECTION
ntlbridge0  bridge    connected  bridge ntl
enp1s0f0    ethernet  connected  ntlbridge0 slave enp1s0f0 
enp1s0f1    ethernet  connected  ntlbridge0 slave enp1s0f1

Further information requested:

ip link show
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp1s0f0:  mtu 1500 qdisc mq master ntlbridge0 state UP mode DEFAULT group default qlen 1000
    link/ether d0:27:xx:xx:xx:40 brd ff:ff:ff:ff:ff:ff
3: enp1s0f1:  mtu 1500 qdisc mq master ntlbridge0 state UP mode DEFAULT group default qlen 1000
    link/ether d0:27:xx:xx:xx:41 brd ff:ff:ff:ff:ff:ff
9: ntlbridge0:  mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether d0:27:xx:xx:xx:40 brd ff:ff:ff:ff:ff:ff

ip addr show
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp1s0f0:  mtu 1500 qdisc mq master ntlbridge0 state UP group default qlen 1000
    link/ether d0:27:xx:xx:xx:40 brd ff:ff:ff:ff:ff:ff
3: enp1s0f1:  mtu 1500 qdisc mq master ntlbridge0 state UP group default qlen 1000
    link/ether d0:27:xx:xx:xx:41 brd ff:ff:ff:ff:ff:ff
9: ntlbridge0:  mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether d0:27:xx:xx:xx:40 brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.67/24 brd 192.168.10.255 scope global dynamic ntlbridge0
       valid_lft 50187sec preferred_lft 50187sec
    inet6 2601:844:4000:xxx:xxx:xxxx:xxxx:ac61/64 scope global noprefixroute dynamic 
       valid_lft 2367sec preferred_lft 2367sec
    inet6 fe80::1e94:xxxx:xxxx:77ba/64 scope link 
       valid_lft forever preferred_lft forever

ip route show
default via 192.168.10.1 dev ntlbridge0  proto static  metric 425 
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1 linkdown 
192.168.10.0/24 dev ntlbridge0  proto kernel  scope link  src 192.168.10.67  metric 425 
192.168.10.0/24 dev ntlbridge0  proto kernel  scope link  src 192.168.10.67  metric 426 
192.168.122.0/24 dev virbr0  proto kernel  scope link  src 192.168.122.1 linkdown

brctl show
bridge name     bridge id       STP enabled interfaces
docker0         8000.0242910e3b7a   no      
ntlbridge0      8000.d027xxxxxx40   yes     enp1s0f0
                                enp1s0f1

Best Answer

Soooooooo here's the funny thing about bridging in modern kernels... you can tell the kernel to send packets that pass through the bridge through iptables, and they're treated exactly the same as if they were forwarded at layer 3. It is rare that you actually want this, and yet some distros or kernel versions or something turn that feature on by default (probably for security, which is understandable if frustrating).

Check the values of the sysctls /proc/sys/net/bridge/bridge-nf-call-*; if any of those are 1, then the corresponding filtering system is being used for matching packets (iptables for IPv4 packets, ip6tables for IPv6 packets). Set them to 0 to turn that thing off, and you may see a pleasant improvement.

There really isn't enough in your question to tell for sure that's what is going on, but the bridge-nf-call-* sysctls are always the first place I look when bridging is playing up.

Beyond that, without pcaps on all the interfaces involved, it's nearly impossible to tell what's going on and where the problem may lie.