I am told that, for those of us who have advanced hardware and firmware, the accepted bridge solution works. But for me, using open source linux firmware for ath9k, combined with an open source atheros qualcom chip set, the above answer does not work. So, if you try the bridge and you get the 'Operation Not Permitted' error...
WiFi and Ethernet cannot be directly bridged via the Debian bridge-utils package containing brctl because the level 3 package protocols are different. WiFi assumes that every packet comes from another source and includes that information, while Ethernet does not. Spoofing/cheating methods exist, but they are recognized as a threat by the outside world and blocked.
You must rebuild the level 3 package to convert Ethernet headers to WiFi headers via a Linux service called dnsmasq.service which masquerades packages, rebuilding the level 3 headers. The declaration of what is to happen may be created via Linux iptables wnich may employ a process called Network Address Translation.
#!/bin/bash
#
# wifi2eth
#
# Tested on Debian GNU/Linux bullseye/sid system.
# Used to connect a Magic Jack Ethernet device so that I may use a corded telephone through the computer which connects to a cellular to WiFi hot-spot device (the MiFi-8000).
# There are certain numbers which, when dialed out, where I can hear the person I called, but they cannot hear me. The problem was resolved by adding UNTRACKED to the list of packets which should be forwarded from WiFi to Ethernet (the telephone).
# When an incoming packet is marked as UNTRACKED, then the state mechanism is broken. I have no problem yet, but if UNTRACKED is used by a sender which is not part of VOIP, then that will create a browsing problem. I would prefer my computer disrespect UNTRACKED requests.
#
# This program creates a functioning WiFi to Ethernet 'bridge'
#
# Step 0: Reset
{ # the redirect of this block also hides bash -x
sudo ifdown --all
for zUp in $(ip addr show | sed -nEe 's/[0-9]+: ([^:]+).* UP .*/\1/p' | tr '\n' ' '); do
sudo ip link set "$zUp" down # force interface down which ifdown was unable to bring down
done
sudo iptables -F
sudo iptables -t nat -F
sudo systemctl stop dnsmasq.service
sudo systemctl disable dnsmasq.service
} &> /dev/null
sudo ifup --all
sudo ifup wlNet 2>&1 | grep -Ee "^Listening on" -e "^DHCPDISCOVER" -e "^bound to"
if [[ $(ip link show wlNet) = *' state DOWN '* ]]; then
echo "$(tput setaf 1)!!! $(basename "$0"): Could not ifup wlNet !!!$(tput sgr0)"
exit
fi
# Step 1: Create the iptables
aEthernet="enTele" # the Ethernet output I want for magicJack
aWireless="wlNet" # the functioning wireless input
aNext=192.168.2 # the next subnet after 192.168.1
aIp_address="$aNext.1" # use the next subnet to create internal network
aNetmask="255.255.255.0" # the network mask
# aNetwork="$aNext.0" # the external inet representing the internal block
# aBroadcast="$aNext.255" # the broadcast IP
aDhcp_range_start="$aNext.50" # inet addresses to be available in subnet
aDhcp_range_end="$aNext.100" # inet addresses to be available in subnet
aDhcp_time="12h" # address lease duration
sudo iptables --flush
sudo iptables -F
sudo iptables -A FORWARD -i $aWireless -o $aEthernet -m state --state RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
sudo iptables -A FORWARD -i $aEthernet -o $aWireless -j ACCEPT
sudo iptables -t nat -F
sudo iptables -t nat -A POSTROUTING -o $aWireless -j MASQUERADE
# Step 2: Turn on IP forwarding.
sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
sudo ifconfig $aEthernet $aIp_address netmask $aNetmask
# May also have to uncomment net.ipv4.ip_forward=1 in /etc/sysctl.conf
# Remove possible default route created by dhcpcd.
# Hide error if route does not exist.
sudo ip route del 0/0 dev $aEthernet &> /dev/null
# Step 3: Reconfigure and restart domain name masquerade.
sudo systemctl stop dnsmasq
cat - > /tmp/custom-dnsmasq.conf <<-EOF
interface=$aEthernet
bind-interfaces
server=1.1.1.1
domain-needed
bogus-priv
dhcp-range=$aDhcp_range_start,$aDhcp_range_end,$aDhcp_time
EOF
sudo rm -r /etc/dnsmasq.d/*
sudo mv /tmp/custom-dnsmasq.conf /etc/dnsmasq.d/custom-dnsmasq.conf
sudo systemctl start dnsmasq
# Show off what we did
sudo iptables-save | grep --no-group-separator -e '^-A' -e '^*' | grep -ve '^#'
#################
# End Of Code
#################
#
# The iptables language:
#
# iptables understands ipv4 (ip6tables understand ipv6 (not used))
# apt-get install iptables # comes preinstalled with debian
#
# An iptable stores a chain of rules which redirects packets.
# The first match in a chain determines the packet destination.
# The iptables table name determines when and how the table is used.
# An iptables name is not random or arbitrary.
#
# --table 'filter' is the default and is for firewall creation
# --table 'mangle' is for chaning packet headers (TTL values...)
# --table 'nat' is for routing packets to different hosts via Network Address Translation
# --table 'raw' is a stateful firewall (knows if packet is part of a new or existing connection...)
#
# Chains of a table determine the inspection point.
# PREROUTING chain is for arriving packets in tables 'nat', 'mangle' and 'raw'.
# INPUT is chain for packets going to local process in tables 'mangle' and 'filter'.
# OUTPUT is chain for packets from a process in tables 'raw', 'mangle', 'nat', and 'filter'.
# FORWARD is chain for packets routed through localhost in tables 'mangle', 'filter'.
# POSTROUTING is chain for exiting packets in tables 'nat', 'mangle'.
# MASQUERADE chain...
# When it receives a datagram from a computer on the LAN
# it takes note of the type of datagram it is, "TCP," "UDP," "ICMP," etc.
# and modifies the datagram so that it looks like it was generated by the router machine itself
# and remembers that it has done so.
# It then transmits the datagram onto the Internet with its single connected IP address.
# When the destination host receives this datagram,
# it believes the datagram has come from the routing host and sends any reply datagrams back to that address.
# When the Linux masquerade router receives a datagram from its Internet connection,
# it looks in its table of established masqueraded connections
# to see if this datagram actually belongs to a computer on the LAN,
# if it does, it reverses the modification it did on the forward path
# and transmits the datagram to the LAN computer.
#
# The target of a rule defines what happens to matched packets.
# ACCEPT is the default which forwards or allows the packet.
# DROP acts as if the packet did not exist.
# REJECT responds with an error (then drop).
# LOG creates a kernel log entry (in /var/log/syslog or /var/log/messesages) (then drop).
#
# The iptables interface:
#
# sudo iptables
# -L|--list -v|--verbose list current ip table entries (no --table shows filter table)
# -F|--flush empty all ip table entries (no --table flushes filter table)
# -A|--append creates a new rule
# -j|--jump where to send the packet if the packet matches the rule
# -i|--in-interface where packet must come for for a match
# -o|--out-interface where packet must be going to for for a match
# -m|--match state list,of,states allowed or a match
# note: see man iptables for many other types of matching rules
#
# Packets have a state:
# NEW for the very first packet of a connection
# ESTABLISHED for packets that are part of an existing connection
# RELATED for packets related to another established connection (ftp)
# INVALID for packets whose state is unknown or improper
# UNTRACKED for packets specifically exempted from connection tracking
# DNAT for packets whose destination address was changed by the table
# SNAT for packets whose source address was changed by the table
#
# Anything you block on the INPUT chain, you can’t access either.
# --state RELATED,ESTABLISHED --jump ACCEPT declares "allow existing connections to continue"
#
# Save/restore iptables:
# Once declared, iptables may be saved and restored to/from files of your choice.
# $ sudo iptables-save > iptables.rules # write current rules to configuration file
# $ sudo iptables-restore < iptables.rules # restore rules from configuration file
# $ sudo apt-get install iptables-persistent # package for automated iptables-save/restore
Above is a program needing chmod +x which creates the NAT forwarding 'bridge' when executed. It will not automatically create the 'bridge' when you reboot.
Note: Packages like network-manager, wicd, connman, etc. all do their own thing. Such packages add configuration, GUI, and control layers which, in my opinion, serve only to convolute everything. Uninstall all of them. This method uses only packages which actually perform a required task: dnsmasq, iptables, and wpasupplicant. The simpler you system, the more comprehendible and reliable your solution.
Basic commands:
$ ip addr show # list every network interface and its current situation
$ sudo ifup INTERFACE # raise interface declared in /etc/network/interfaces
$ sudo ifdown INTERFACE # lower interface declared in /etc/network/interfaces
Best wishes in your pursuit to remain totally open source.
brctl addbr br0
, adding both devices to the bridge withbrctl addif br0 device
, and then setting your original Ethernet address and route onbr0
?