Merge branch 'go'
This commit is contained in:
parent
e895bf322a
commit
8051775b2c
|
@ -1,6 +1,7 @@
|
|||
.idea
|
||||
config/*.sh
|
||||
!config/*.sh.example
|
||||
go/wlan2eth/wlan2eth
|
||||
|
||||
# ---> Python
|
||||
# Byte-compiled / optimized / DLL files
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
`sudo apt install libpcap-dev gcc`
|
||||
|
||||
```bash
|
||||
wlan2eth build wlan2eth.wlan2eth
|
||||
sudo ./wlan2eth
|
||||
```
|
||||
|
||||
If build fails, try `CGO_ENABLED=1`
|
||||
|
||||
# Issues
|
||||
|
||||
- To prevent forwarding duplicates, incoming hash of in packets are cached and checked against subsequent packets. This may cause issues where duplicate packets are blocked.
|
|
@ -0,0 +1,63 @@
|
|||
package arp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/sirupsen/logrus"
|
||||
"net"
|
||||
"syscall"
|
||||
"wlan2eth/logger"
|
||||
)
|
||||
|
||||
func HandleARPRequest(packet gopacket.Packet, srcSocket, dstSocket int, srcName, dstName string, srcMAC, dstMAC net.HardwareAddr, wlan0MAC net.HardwareAddr, eth0 string) {
|
||||
log := logger.GetLogger()
|
||||
|
||||
arpLayer := packet.Layer(layers.LayerTypeARP).(*layers.ARP)
|
||||
ethLayer := packet.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
|
||||
|
||||
// Add the client to the bridgedClients map
|
||||
srcIP := net.IP(arpLayer.SourceProtAddress)
|
||||
srcHwAddr := arpLayer.SourceHwAddress
|
||||
AddBridgedClient(srcIP, srcHwAddr, wlan0MAC, eth0)
|
||||
|
||||
// Check if the ARP request is an ARP announcement
|
||||
isARPAnnouncement := bytes.Equal(arpLayer.SourceProtAddress, arpLayer.DstProtAddress)
|
||||
|
||||
// If the ARP request is an ARP announcement, use the MAC address of the wlan0 interface
|
||||
if isARPAnnouncement {
|
||||
arpLayer.SourceHwAddress = dstMAC
|
||||
} else {
|
||||
// Modify the Ethernet source MAC address to appear as if it originated from the wlan0 interface
|
||||
arpLayer.SourceHwAddress = wlan0MAC // Use the MAC address of the wlan0 interface
|
||||
}
|
||||
|
||||
// Create an Ethernet frame for the proxied ARP request
|
||||
ethLayer.SrcMAC = wlan0MAC // Use the MAC address of the eth0 interface
|
||||
|
||||
// Serialize the proxied ARP request
|
||||
buf := gopacket.NewSerializeBuffer()
|
||||
opts := gopacket.SerializeOptions{
|
||||
FixLengths: true,
|
||||
ComputeChecksums: true,
|
||||
}
|
||||
err := gopacket.SerializeLayers(buf, opts, ethLayer, arpLayer)
|
||||
if err != nil {
|
||||
log.Errorf("Error serializing proxied ARP request: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Send the proxied ARP request on the destination socket
|
||||
_, err = syscall.Write(dstSocket, buf.Bytes())
|
||||
if err != nil {
|
||||
log.Errorf("Error sending proxied ARP request on %s: %v", dstName, err)
|
||||
return
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"IP": srcIP.String(),
|
||||
"MAC": net.HardwareAddr(srcHwAddr).String(),
|
||||
}).Debugf("Forwarded ARP request from %s to %s\n", srcName, dstName)
|
||||
|
||||
//log.Debugf("Forwarded ARP request from %s to %s\n", srcName, dstName)
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package arp
|
||||
|
||||
import (
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/sirupsen/logrus"
|
||||
"net"
|
||||
"syscall"
|
||||
"wlan2eth/logger"
|
||||
)
|
||||
|
||||
//var bridgedClients = make(map[string]net.HardwareAddr)
|
||||
//var bridgedClientsLock sync.Mutex
|
||||
|
||||
func HandleARPResponse(packet gopacket.Packet, srcSocket, dstSocket int, srcName, dstName string, srcMAC, dstMAC net.HardwareAddr, eth0MAC net.HardwareAddr) {
|
||||
log := logger.GetLogger()
|
||||
|
||||
arpLayer := packet.Layer(layers.LayerTypeARP).(*layers.ARP)
|
||||
|
||||
targetIP := net.IP(arpLayer.DstProtAddress)
|
||||
clientMAC, ok := bridgedClients[targetIP.String()]
|
||||
if !ok {
|
||||
return // Not a bridged client, ignore the ARP response
|
||||
}
|
||||
|
||||
// Forward the ARP response to the client
|
||||
ethLayer := packet.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
|
||||
ethLayer.DstMAC = clientMAC.MAC
|
||||
ethLayer.SrcMAC = eth0MAC
|
||||
arpLayer.DstHwAddress = clientMAC.MAC
|
||||
arpLayer.SourceHwAddress = eth0MAC
|
||||
|
||||
// Serialize the modified ARP response
|
||||
buf := gopacket.NewSerializeBuffer()
|
||||
opts := gopacket.SerializeOptions{
|
||||
FixLengths: true,
|
||||
ComputeChecksums: true,
|
||||
}
|
||||
err := gopacket.SerializeLayers(buf, opts, ethLayer, arpLayer)
|
||||
if err != nil {
|
||||
log.Errorf("Error serializing ARP response: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Send the modified ARP response on the destination socket
|
||||
_, err = syscall.Write(dstSocket, buf.Bytes())
|
||||
if err != nil {
|
||||
log.Errorf("Error sending ARP response on %s: %v", dstName, err)
|
||||
return
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"IP": targetIP.String(),
|
||||
"MAC": clientMAC.StringMAC(),
|
||||
}).Debugf("Forwarded ARP request from %s to %s\n", srcName, dstName)
|
||||
|
||||
//log.Debugf("Forwarded ARP response from %s to %s\n", srcName, dstName)
|
||||
}
|
||||
|
||||
//func AddBridgedClient(ip net.IP, mac net.HardwareAddr, wlan0MAC net.HardwareAddr) {
|
||||
// log := logger.GetLogger()
|
||||
//
|
||||
// // Ignore the wlan0 MAC address
|
||||
// if bytes.Equal(mac, wlan0MAC) {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// bridgedClientsLock.Lock()
|
||||
// defer bridgedClientsLock.Unlock()
|
||||
//
|
||||
// ipStr := ip.String()
|
||||
// if _, exists := bridgedClients[ipStr]; !exists {
|
||||
// bridgedClients[ipStr] = mac
|
||||
// log.WithFields(logrus.Fields{
|
||||
// "IP": ipStr,
|
||||
// "MAC": mac,
|
||||
// }).Info("Added bridged client")
|
||||
// }
|
||||
//}
|
|
@ -0,0 +1,114 @@
|
|||
package arp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/sirupsen/logrus"
|
||||
"net"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"time"
|
||||
"wlan2eth/logger"
|
||||
)
|
||||
|
||||
type ClientInfo struct {
|
||||
MAC net.HardwareAddr
|
||||
Timestamp time.Time
|
||||
}
|
||||
|
||||
func (c ClientInfo) StringMAC() string {
|
||||
return c.MAC.String()
|
||||
}
|
||||
|
||||
var bridgedClients = make(map[string]ClientInfo)
|
||||
var bridgedClientsLock sync.Mutex
|
||||
|
||||
func AddBridgedClient(ip net.IP, mac net.HardwareAddr, wlan0MAC net.HardwareAddr, eth0 string) {
|
||||
log := logger.GetLogger()
|
||||
|
||||
// Ignore the wlan0 MAC address
|
||||
if bytes.Equal(mac, wlan0MAC) {
|
||||
return
|
||||
}
|
||||
|
||||
bridgedClientsLock.Lock()
|
||||
defer bridgedClientsLock.Unlock()
|
||||
|
||||
ipStr := ip.String()
|
||||
if clientInfo, exists := bridgedClients[ipStr]; !exists {
|
||||
bridgedClients[ipStr] = ClientInfo{MAC: mac, Timestamp: time.Now()}
|
||||
//AddClientRoutes(eth0)
|
||||
log.WithFields(logrus.Fields{
|
||||
"IP": ipStr,
|
||||
"MAC": mac,
|
||||
"Interface": eth0,
|
||||
}).Info("Added bridged client")
|
||||
} else {
|
||||
// Update the timestamp if the client already exists
|
||||
clientInfo.Timestamp = time.Now()
|
||||
bridgedClients[ipStr] = clientInfo
|
||||
}
|
||||
}
|
||||
|
||||
func removeTimedOutClients(timeout time.Duration) {
|
||||
log := logger.GetLogger()
|
||||
bridgedClientsLock.Lock()
|
||||
defer bridgedClientsLock.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
for ip, clientInfo := range bridgedClients {
|
||||
if now.Sub(clientInfo.Timestamp) > timeout {
|
||||
delete(bridgedClients, ip)
|
||||
log.WithFields(logrus.Fields{
|
||||
"IP": ip,
|
||||
"MAC": clientInfo.StringMAC(),
|
||||
}).Info("Removed timed-out bridged client")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func StartClientTimeoutChecker(timeout time.Duration, checkInterval time.Duration) {
|
||||
ticker := time.NewTicker(checkInterval)
|
||||
for range ticker.C {
|
||||
removeTimedOutClients(timeout)
|
||||
}
|
||||
}
|
||||
|
||||
func GetClientMACByIP(ip net.IP) (net.HardwareAddr, bool) {
|
||||
bridgedClientsLock.Lock()
|
||||
defer bridgedClientsLock.Unlock()
|
||||
|
||||
ipStr := ip.String()
|
||||
if clientInfo, exists := bridgedClients[ipStr]; exists {
|
||||
return clientInfo.MAC, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func AddClientToARPTable(ip net.IP, mac net.HardwareAddr, iface string) {
|
||||
log := logger.GetLogger()
|
||||
|
||||
arpCmd := exec.Command("arp", "-i", iface, "-s", ip.String(), mac.String())
|
||||
err := arpCmd.Run()
|
||||
if err != nil {
|
||||
log.Errorf("Error adding client to ARP table on %s: %v", iface, err)
|
||||
} else {
|
||||
log.Infof("Added client %s (%s) to ARP table on %s", ip.String(), mac.String(), iface)
|
||||
}
|
||||
}
|
||||
|
||||
func AddClientRoutes(eth0 string) {
|
||||
log := logger.GetLogger()
|
||||
|
||||
bridgedClientsLock.Lock()
|
||||
defer bridgedClientsLock.Unlock()
|
||||
|
||||
for ipStr := range bridgedClients {
|
||||
cmd := exec.Command("ip", "route", "add", ipStr, "dev", eth0)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.Errorf("Error adding route for IP %s: %v", ipStr, err)
|
||||
} else {
|
||||
log.Infof("Added route for IP %s", ipStr)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/vishvananda/netlink"
|
||||
"net"
|
||||
"wlan2eth/logger"
|
||||
)
|
||||
|
||||
func GetInterfacesHW(wlan0 string, eth0 string) (net.HardwareAddr, net.HardwareAddr) {
|
||||
log := logger.GetLogger()
|
||||
|
||||
// Get the hardware address of the host's interfaces
|
||||
var wlan0MAC net.HardwareAddr
|
||||
var eth0MAC net.HardwareAddr
|
||||
|
||||
var err error
|
||||
wlan0MAC, err = GetInterfaceMAC(wlan0)
|
||||
if err != nil {
|
||||
log.Fatalf("Error getting MAC address of %s: %v", wlan0, err)
|
||||
}
|
||||
eth0MAC, err = GetInterfaceMAC(eth0)
|
||||
if err != nil {
|
||||
log.Fatalf("Error getting MAC address of %s: %v", eth0, err)
|
||||
}
|
||||
return wlan0MAC, eth0MAC
|
||||
}
|
||||
|
||||
func FlushIPAddresses(ifaceName string) error {
|
||||
// Get the network interface by name
|
||||
iface, err := netlink.LinkByName(ifaceName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get interface %s: %v", ifaceName, err)
|
||||
}
|
||||
|
||||
// Get all IP addresses associated with the interface
|
||||
addrs, err := netlink.AddrList(iface, netlink.FAMILY_ALL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get IP addresses for interface %s: %v", ifaceName, err)
|
||||
}
|
||||
|
||||
// Iterate through the IP addresses and remove them
|
||||
for _, addr := range addrs {
|
||||
err := netlink.AddrDel(iface, &addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to remove IP address %s from interface %s: %v", addr.IP.String(), ifaceName, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetIPByInterface(ifaceName string) net.IP {
|
||||
log := logger.GetLogger()
|
||||
|
||||
iface, err := net.InterfaceByName(ifaceName)
|
||||
if err != nil {
|
||||
log.Errorf("Error getting interface by name %s: %v", ifaceName, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
log.Errorf("Error getting addresses for interface %s: %v", ifaceName, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
ip, _, err := net.ParseCIDR(addr.String())
|
||||
if err != nil {
|
||||
log.Errorf("Error parsing CIDR for address %s: %v", addr.String(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
if ip.To4() != nil {
|
||||
return ip
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package bridge
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/mdlayher/arp"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func GetInterfaceMAC(interfaceName string) (net.HardwareAddr, error) {
|
||||
iface, err := net.InterfaceByName(interfaceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return iface.HardwareAddr, nil
|
||||
}
|
||||
|
||||
func getInterfaceMTU(ifaceName string) (int, error) {
|
||||
iface, err := net.InterfaceByName(ifaceName)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return iface.MTU, nil
|
||||
}
|
||||
|
||||
func getDefaultGatewayIP() (net.IP, error) {
|
||||
file, err := os.Open("/proc/net/route")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
fields := strings.Fields(scanner.Text())
|
||||
if len(fields) < 3 || fields[0] == "Iface" {
|
||||
continue
|
||||
}
|
||||
|
||||
dest, err := strconv.ParseUint(fields[1], 16, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if dest == 0 {
|
||||
gateway, err := strconv.ParseUint(fields[2], 16, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return net.IPv4(byte(gateway), byte(gateway>>8), byte(gateway>>16), byte(gateway>>24)), nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("default gateway not found")
|
||||
}
|
||||
|
||||
func GetGatewayMAC(wlan0 string) (net.HardwareAddr, error) {
|
||||
// Get the default gateway IP
|
||||
gatewayIP, err := getDefaultGatewayIP()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Convert gatewayIP (net.IP) to netaddr.IP
|
||||
gatewayIPAddr, err := netip.ParseAddr(gatewayIP.String())
|
||||
|
||||
// Get the network interface by name
|
||||
iface, err := net.InterfaceByName(wlan0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting network interface: %v", err)
|
||||
}
|
||||
|
||||
// Create an ARP client using the network interface
|
||||
client, err := arp.Dial(iface)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating ARP client: %v", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// Resolve the gateway's MAC address using ARP
|
||||
gatewayMAC, err := client.Resolve(gatewayIPAddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error resolving gateway MAC address: %v", err)
|
||||
}
|
||||
|
||||
return gatewayMAC, nil
|
||||
}
|
||||
|
||||
func EnablePathMTUDiscovery(srcSocket int, srcName string) error {
|
||||
return syscall.SetsockoptInt(srcSocket, syscall.IPPROTO_IP, syscall.IP_MTU_DISCOVER, syscall.IP_PMTUDISC_DO)
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package bridge
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func CreateRawSocket(ifaceName string) (int, error) {
|
||||
// Create a raw socket
|
||||
sock, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, int(htons(syscall.ETH_P_ALL)))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Get the interface index
|
||||
iface, err := net.InterfaceByName(ifaceName)
|
||||
if err != nil {
|
||||
syscall.Close(sock)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Bind the socket to the interface
|
||||
addr := syscall.SockaddrLinklayer{
|
||||
Protocol: htons(syscall.ETH_P_ALL),
|
||||
Ifindex: iface.Index,
|
||||
}
|
||||
err = syscall.Bind(sock, &addr)
|
||||
if err != nil {
|
||||
syscall.Close(sock)
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return sock, nil
|
||||
}
|
||||
|
||||
func htons(i uint16) uint16 {
|
||||
return (i<<8)&0xff00 | i>>8
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package dhcp
|
||||
|
||||
import (
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"net"
|
||||
"syscall"
|
||||
"wlan2eth/logger"
|
||||
)
|
||||
|
||||
func HandleDHCPRequest(packet gopacket.Packet, srcSocket, dstSocket int, srcName, dstName string, srcMAC, dstMAC net.HardwareAddr, modifyClientSrc bool) {
|
||||
log := logger.GetLogger()
|
||||
// Get the DHCP layer
|
||||
dhcpLayer := packet.Layer(layers.LayerTypeDHCPv4)
|
||||
if dhcpLayer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
dhcp := dhcpLayer.(*layers.DHCPv4)
|
||||
|
||||
// Store the client's MAC address and the transaction ID in the map
|
||||
transactionIDToClientMAC[dhcp.Xid] = dhcp.ClientHWAddr
|
||||
|
||||
// Modify the DHCP client hardware address to appear as if it originated from the wlan0 interface
|
||||
if modifyClientSrc {
|
||||
dhcp.ClientHWAddr = dstMAC
|
||||
}
|
||||
|
||||
// Get the Ethernet layer and cast it to its type
|
||||
ethLayer := packet.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
|
||||
|
||||
// Modify the Ethernet source MAC address to appear as if it originated from the wlan0 interface
|
||||
ethLayer.SrcMAC = dstMAC
|
||||
|
||||
// Get the IPv4 and UDP layers and cast them to their respective types
|
||||
ipLayer := packet.Layer(layers.LayerTypeIPv4).(*layers.IPv4)
|
||||
udpLayer := packet.Layer(layers.LayerTypeUDP).(*layers.UDP)
|
||||
|
||||
// Set the network layer for the UDP checksum computation
|
||||
err := udpLayer.SetNetworkLayerForChecksum(ipLayer)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to set the network layer for the UDP checksum computation in handleDHCPRequest(). This is a bug???")
|
||||
return
|
||||
}
|
||||
|
||||
// Serialize the modified packet
|
||||
buf := gopacket.NewSerializeBuffer()
|
||||
opts := gopacket.SerializeOptions{
|
||||
FixLengths: true,
|
||||
ComputeChecksums: true,
|
||||
}
|
||||
err = gopacket.SerializeLayers(buf, opts, ethLayer, ipLayer, udpLayer, dhcp)
|
||||
if err != nil {
|
||||
log.Errorf("Error serializing DHCP request: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Send the modified DHCP request on the destination socket
|
||||
_, err = syscall.Write(dstSocket, buf.Bytes())
|
||||
if err != nil {
|
||||
log.Errorf("Error sending DHCP request on %s: %v", dstName, err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugf("Forwarded DHCP request from %s to %s\n", srcName, dstName)
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package dhcp
|
||||
|
||||
import (
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"net"
|
||||
"syscall"
|
||||
"wlan2eth/arp"
|
||||
"wlan2eth/logger"
|
||||
)
|
||||
|
||||
func HandleDHCPResponse(packet gopacket.Packet, srcSocket, dstSocket int, srcName, dstName string, srcMAC, dstMAC net.HardwareAddr, wlan0MAC net.HardwareAddr, modifyClientSrc bool, eth0 string) {
|
||||
log := logger.GetLogger()
|
||||
|
||||
// Get the DHCP layer
|
||||
dhcpLayer := packet.Layer(layers.LayerTypeDHCPv4)
|
||||
if dhcpLayer == nil {
|
||||
log.Error("DHCP layer not found in the packet")
|
||||
return
|
||||
}
|
||||
|
||||
// Update the client's IP address in the bridgedClients map
|
||||
dhcp := dhcpLayer.(*layers.DHCPv4)
|
||||
clientIP := dhcp.YourClientIP
|
||||
if !clientIP.IsUnspecified() {
|
||||
arp.AddBridgedClient(clientIP, dhcp.ClientHWAddr, wlan0MAC, eth0)
|
||||
}
|
||||
|
||||
clientMAC, ok := transactionIDToClientMAC[dhcp.Xid]
|
||||
if !ok {
|
||||
log.Errorf("Unknown transaction ID: %v", dhcp.Xid)
|
||||
return
|
||||
}
|
||||
|
||||
// Set the address the DHCP packet to clientMAC (a bridged client behind eth0)
|
||||
if modifyClientSrc {
|
||||
dhcp.ClientHWAddr = clientMAC
|
||||
}
|
||||
|
||||
// Get the Ethernet layer and cast it to its type
|
||||
ethLayer := packet.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
|
||||
|
||||
// Modify the Ethernet source MAC address of the DHCP packet to clientMAC
|
||||
ethLayer.SrcMAC = clientMAC
|
||||
|
||||
// Get the IPv4 and UDP layers and cast them to their respective types
|
||||
ipLayer := packet.Layer(layers.LayerTypeIPv4).(*layers.IPv4)
|
||||
udpLayer := packet.Layer(layers.LayerTypeUDP).(*layers.UDP)
|
||||
|
||||
// Set the network layer for the UDP checksum computation
|
||||
udpLayer.SetNetworkLayerForChecksum(ipLayer)
|
||||
|
||||
// Serialize the modified packet
|
||||
buf := gopacket.NewSerializeBuffer()
|
||||
opts := gopacket.SerializeOptions{
|
||||
FixLengths: true,
|
||||
ComputeChecksums: true,
|
||||
}
|
||||
err := gopacket.SerializeLayers(buf, opts, ethLayer, ipLayer, udpLayer, dhcp)
|
||||
if err != nil {
|
||||
log.Errorf("Error serializing DHCP response: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Send the modified DHCP response on the destination socket
|
||||
_, err = syscall.Write(dstSocket, buf.Bytes())
|
||||
if err != nil {
|
||||
log.Errorf("Error sending DHCP response on %s: %v", dstName, err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugf("Forwarded DHCP response from %s to %s\n", srcName, dstName)
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package dhcp
|
||||
|
||||
import "net"
|
||||
|
||||
var transactionIDToClientMAC = make(map[uint32]net.HardwareAddr)
|
|
@ -0,0 +1,21 @@
|
|||
module wlan2eth
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/google/gopacket v1.1.19
|
||||
github.com/mdlayher/arp v0.0.0-20220512170110-6706a2966875
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/vishvananda/netlink v1.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 // indirect
|
||||
github.com/mdlayher/packet v1.1.2 // indirect
|
||||
github.com/mdlayher/socket v0.4.1 // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect
|
||||
golang.org/x/net v0.11.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/sys v0.9.0 // indirect
|
||||
)
|
|
@ -0,0 +1,61 @@
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/mdlayher/arp v0.0.0-20220512170110-6706a2966875 h1:ql8x//rJsHMjS+qqEag8n3i4azw1QneKh5PieH9UEbY=
|
||||
github.com/mdlayher/arp v0.0.0-20220512170110-6706a2966875/go.mod h1:kfOoFJuHWp76v1RgZCb9/gVUc7XdY877S2uVYbNliGc=
|
||||
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 h1:2oDp6OOhLxQ9JBoUuysVz9UZ9uI6oLUbvAZu0x8o+vE=
|
||||
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118/go.mod h1:ZFUnHIVchZ9lJoWoEGUg8Q3M4U8aNNWA3CVSUTkW4og=
|
||||
github.com/mdlayher/packet v1.0.0/go.mod h1:eE7/ctqDhoiRhQ44ko5JZU2zxB88g+JH/6jmnjzPjOU=
|
||||
github.com/mdlayher/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY=
|
||||
github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU+x0kew4=
|
||||
github.com/mdlayher/socket v0.2.1/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
|
||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
|
||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
@ -0,0 +1,32 @@
|
|||
package logger
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type ColorFormatter struct {
|
||||
}
|
||||
|
||||
var log *logrus.Logger
|
||||
|
||||
func init() {
|
||||
log = logrus.New()
|
||||
|
||||
// Set log output format
|
||||
log.SetFormatter(&logrus.TextFormatter{})
|
||||
customFormatter := new(logrus.TextFormatter)
|
||||
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
|
||||
customFormatter.FullTimestamp = true
|
||||
log.SetFormatter(customFormatter)
|
||||
|
||||
}
|
||||
|
||||
// InitLogger initializes the global logger with the specified log level
|
||||
func InitLogger(logLevel logrus.Level) {
|
||||
log.SetLevel(logLevel)
|
||||
}
|
||||
|
||||
// GetLogger returns the global logger instance
|
||||
func GetLogger() *logrus.Logger {
|
||||
return log
|
||||
}
|
|
@ -0,0 +1,281 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/sirupsen/logrus"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
"wlan2eth/arp"
|
||||
"wlan2eth/bridge"
|
||||
"wlan2eth/dhcp"
|
||||
"wlan2eth/logger"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
mode string
|
||||
debug bool
|
||||
packets bool
|
||||
dhcpModifySrc bool
|
||||
eth string
|
||||
wlan string
|
||||
help bool
|
||||
}
|
||||
|
||||
var onlyDHCP bool
|
||||
var dhcpModifyClientSrc bool
|
||||
var printPackets bool
|
||||
|
||||
var wlan0 string
|
||||
var wlan0MAC net.HardwareAddr
|
||||
var eth0 string
|
||||
var eth0MAC net.HardwareAddr
|
||||
var gatewayMAC net.HardwareAddr
|
||||
|
||||
var log *logrus.Logger
|
||||
|
||||
// TODO: don't let the bridged client see the host's traffic
|
||||
// TODO: faster detecting of bridged clients
|
||||
// TODO: manually fragment packets to fix the error `Error writing packet to wlan0: message too long`
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
cfg := parseArgs()
|
||||
if cfg.help {
|
||||
flag.Usage()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
wlan0 = cfg.wlan
|
||||
eth0 = cfg.eth
|
||||
|
||||
if cfg.mode == "dhcp" {
|
||||
onlyDHCP = true
|
||||
} else {
|
||||
onlyDHCP = false
|
||||
}
|
||||
dhcpModifyClientSrc = cfg.dhcpModifySrc
|
||||
printPackets = cfg.packets
|
||||
|
||||
var dhcpMode string
|
||||
if cfg.dhcpModifySrc {
|
||||
dhcpMode = "rewrite"
|
||||
} else {
|
||||
dhcpMode = "translate"
|
||||
}
|
||||
|
||||
if cfg.debug {
|
||||
logger.InitLogger(logrus.DebugLevel)
|
||||
} else {
|
||||
logger.InitLogger(logrus.InfoLevel)
|
||||
}
|
||||
log = logger.GetLogger()
|
||||
|
||||
err = bridge.FlushIPAddresses(eth0)
|
||||
if err != nil {
|
||||
log.Fatalf("Error flushing IP addresses from interface %s: %v\n", eth0, err)
|
||||
} else {
|
||||
log.Debugf("Successfully flushed IP addresses from interface %s\n", eth0)
|
||||
}
|
||||
|
||||
wlan0MAC, err = bridge.GetInterfaceMAC(wlan0)
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating raw socket for wlan0: %v", err)
|
||||
}
|
||||
eth0MAC, err = bridge.GetInterfaceMAC(eth0)
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating raw socket for eth0: %v", err)
|
||||
}
|
||||
|
||||
ethSocket, err := bridge.CreateRawSocket(eth0)
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating raw socket for eth0: %v", err)
|
||||
}
|
||||
defer syscall.Close(ethSocket)
|
||||
|
||||
wlanSocket, err := bridge.CreateRawSocket(wlan0)
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating raw socket for wlan0: %v", err)
|
||||
}
|
||||
defer syscall.Close(wlanSocket)
|
||||
|
||||
if cfg.mode == "dhcp" {
|
||||
gatewayMAC, _ = net.ParseMAC("00:00:00:00:00:00")
|
||||
go forwardPackets(ethSocket, wlanSocket, eth0, wlan0)
|
||||
go forwardPackets(wlanSocket, ethSocket, wlan0, eth0)
|
||||
log.Infof("Started DHCP relay in %s mode\n", dhcpMode)
|
||||
} else if cfg.mode == "proxyarp" {
|
||||
gatewayMAC, err = bridge.GetGatewayMAC(wlan0)
|
||||
if err != nil {
|
||||
log.Fatalf("Error getting gateway MAC address: %v", err)
|
||||
}
|
||||
go forwardPackets(ethSocket, wlanSocket, eth0, wlan0)
|
||||
go forwardPackets(wlanSocket, ethSocket, wlan0, eth0)
|
||||
log.Infof("Started ARP proxy between %s and %s\n", wlan0, eth0)
|
||||
log.Infof("Started DHCP relay in %s mode\n", dhcpMode)
|
||||
}
|
||||
|
||||
go arp.StartClientTimeoutChecker(5*time.Minute, 1*time.Minute)
|
||||
|
||||
select {}
|
||||
}
|
||||
|
||||
func forwardPackets(srcSocket, dstSocket int, srcName string, dstName string) {
|
||||
srcMAC, err := bridge.GetInterfaceMAC(srcName)
|
||||
if err != nil {
|
||||
log.Errorf("Error getting MAC address of %s: %v", srcName, err)
|
||||
}
|
||||
dstMAC, err := bridge.GetInterfaceMAC(dstName)
|
||||
if err != nil {
|
||||
log.Errorf("Error getting MAC address of %s: %v", dstName, err)
|
||||
}
|
||||
|
||||
readBuf := make([]byte, 65536)
|
||||
for {
|
||||
n, _, err := syscall.Recvfrom(srcSocket, readBuf, 0)
|
||||
if err != nil {
|
||||
log.Errorf("Error reading packet from %s: %v", srcName, err)
|
||||
continue
|
||||
}
|
||||
packet := gopacket.NewPacket(readBuf[:n], layers.LayerTypeEthernet, gopacket.Default)
|
||||
|
||||
if packet.ErrorLayer() != nil {
|
||||
log.Errorf("Packet is not in Ethernet format: %v", packet.ErrorLayer().Error())
|
||||
continue
|
||||
}
|
||||
|
||||
ethLayer := packet.Layer(layers.LayerTypeEthernet).(*layers.Ethernet)
|
||||
if ethLayer == nil {
|
||||
log.Error("Packet does not have Ethernet layer.")
|
||||
continue
|
||||
}
|
||||
|
||||
arpLayer := packet.Layer(layers.LayerTypeARP)
|
||||
if arpLayer != nil {
|
||||
arpPacket := arpLayer.(*layers.ARP)
|
||||
if arpPacket.Operation == layers.ARPRequest {
|
||||
arp.HandleARPRequest(packet, srcSocket, dstSocket, srcName, dstName, srcMAC, dstMAC, wlan0MAC, eth0)
|
||||
continue
|
||||
} else if arpPacket.Operation == layers.ARPReply {
|
||||
arp.HandleARPResponse(packet, srcSocket, dstSocket, srcName, dstName, srcMAC, dstMAC, eth0MAC)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
udpLayer := packet.Layer(layers.LayerTypeUDP)
|
||||
if udpLayer != nil {
|
||||
udp := udpLayer.(*layers.UDP)
|
||||
if udp.SrcPort == layers.UDPPort(67) && udp.DstPort == layers.UDPPort(68) {
|
||||
dhcp.HandleDHCPResponse(packet, srcSocket, dstSocket, srcName, dstName, srcMAC, dstMAC, wlan0MAC, dhcpModifyClientSrc, eth0)
|
||||
continue
|
||||
} else if udp.SrcPort == layers.UDPPort(68) && udp.DstPort == layers.UDPPort(67) {
|
||||
dhcp.HandleDHCPRequest(packet, srcSocket, dstSocket, srcName, dstName, srcMAC, dstMAC, dhcpModifyClientSrc)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if onlyDHCP {
|
||||
continue
|
||||
}
|
||||
|
||||
rawPacket := readBuf[:n]
|
||||
|
||||
if len(rawPacket) < 14 {
|
||||
fmt.Println("too short")
|
||||
continue
|
||||
}
|
||||
|
||||
ipv4Layer := packet.Layer(layers.LayerTypeIPv4)
|
||||
|
||||
// Check if the packet is addressed for eth0
|
||||
if bytes.Equal(ethLayer.DstMAC, eth0MAC) {
|
||||
copy(rawPacket[0:6], gatewayMAC) // Modify the destination to gatewayMAC
|
||||
copy(rawPacket[6:12], wlan0MAC) // Modify the source to the address of wlan0
|
||||
} else if ipv4Layer != nil {
|
||||
ipv4Packet := ipv4Layer.(*layers.IPv4)
|
||||
|
||||
// Get the destination IP address
|
||||
dstIP := ipv4Packet.DstIP
|
||||
|
||||
// TODO: add a route to the bridged client so the bridge host can ping them.
|
||||
|
||||
// Check if the packet is addressed for eth0
|
||||
if bytes.Equal(ethLayer.DstMAC, wlan0MAC) {
|
||||
// Get the client's MAC address based on the IP address
|
||||
// Get the client's MAC address based on the IP address
|
||||
clientMAC, found := arp.GetClientMACByIP(dstIP)
|
||||
if found {
|
||||
// Modify the destination to the client's MAC address
|
||||
copy(rawPacket[0:6], clientMAC)
|
||||
} else {
|
||||
// Modify the destination MAC address directly in the raw packet data
|
||||
copy(rawPacket[0:6], dstMAC)
|
||||
}
|
||||
} else {
|
||||
// Modify the destination MAC address directly in the raw packet data
|
||||
copy(rawPacket[0:6], dstMAC)
|
||||
}
|
||||
|
||||
// Modify the source MAC address directly in the raw packet data
|
||||
copy(rawPacket[6:12], srcMAC)
|
||||
} else {
|
||||
log.Debugf("Packet was not IPv4!\n%s", packet)
|
||||
continue
|
||||
}
|
||||
//else {
|
||||
// copy(rawPacket[0:6], dstMAC) // Modify the destination MAC address directly in the raw packet data
|
||||
// copy(rawPacket[6:12], srcMAC) // Modify the source MAC address directly in the raw packet data
|
||||
//}
|
||||
|
||||
_, err = syscall.Write(dstSocket, rawPacket)
|
||||
if err != nil {
|
||||
log.Errorf("Error writing packet to %s: %v", dstName, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if printPackets {
|
||||
log.Debugf("Forwarded packet from %s to %s:\n%s", srcName, dstName, packet)
|
||||
} else {
|
||||
log.Debugf("Forwarded packet from %s to %s", srcName, dstName)
|
||||
}
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func parseArgs() config {
|
||||
var cfg config
|
||||
|
||||
flag.StringVar(&cfg.mode, "mode", "proxyarp", "Mode of operation")
|
||||
flag.BoolVar(&cfg.debug, "d", false, "Enable debug mode")
|
||||
flag.BoolVar(&cfg.debug, "debug", false, "Enable debug mode")
|
||||
flag.BoolVar(&cfg.packets, "p", false, "Print packet info in debug mode")
|
||||
flag.BoolVar(&cfg.packets, "packets", false, "Print packet info in debug mode")
|
||||
flag.BoolVar(&cfg.dhcpModifySrc, "dhcp-modify-src", false, "Modify the source of a DHCP message. The frame source is always modified, but this will modify the \"Client MAC Address\" field as well.")
|
||||
flag.StringVar(&cfg.eth, "eth", "", "Ethernet interface name")
|
||||
flag.StringVar(&cfg.wlan, "wlan", "", "Wireless LAN interface name")
|
||||
flag.BoolVar(&cfg.help, "h", false, "Display help information")
|
||||
flag.BoolVar(&cfg.help, "help", false, "Display help information")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if cfg.eth == "" || cfg.wlan == "" {
|
||||
if !cfg.help {
|
||||
fmt.Println("Error: --eth and --wlan are required")
|
||||
}
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if cfg.mode != "dhcp" && cfg.mode != "proxyarp" {
|
||||
fmt.Println("Error: Invalid mode. Allowed values are 'dhcp' or 'proxyarp'")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
Loading…
Reference in New Issue