How to run infrastructure and adhoc simultaneously

Configuring a single physical Wi-Fi radio to run simultaneous infrastructure (AP) SSIDs alongside ad-hoc (IBSS) or mesh interfaces requires leveraging Linux’s mac80211 subsystem, virtual interface (vif) creation via iw, and multi-interface management via hostapd and networking routing.

Because running AP and Ad-Hoc modes concurrently on the same radio depends heavily on hardware and driver concurrency capabilities, this guide walks through the complete procedure on an Ubuntu Linux environment.

Step 1: Verify Hardware & Driver Concurrency Support

Before creating virtual interfaces, verify that your wireless card supports simultaneous AP and Ad-Hoc (or Mesh) operations on the same physical chip.

  1. List your wireless devices and check supported interface combinations:

    Bash

    iw list | grep -A 20 "Supported interface modes"
    
    
  2. Look specifically at the Valid interface combinations section in the output. It will explicitly state whether combinations like AP + IBSS (Ad-Hoc) or AP + MESH are supported concurrently on the same radio index.

Step 2: Create Virtual Network Interfaces (vifs)

Assuming your physical wireless interface is wlan0, you need to spin up separate virtual interfaces for your Infrastructure APs and your Ad-Hoc/Mesh backbone.

**1.Bring down the physical interface:**Required before modifying virtual interface topologies.

Bash

sudo ip link set wlan0 down

**2.Create the Infrastructure AP virtual interface:**Designated for client connections.

Bash

sudo iw dev wlan0 interface add wlan0_ap type __ap

**3.Create the Ad-Hoc or Mesh virtual interface:**Designated for peer-to-peer or backbone nodes.

Bash

# For traditional Ad-Hoc (IBSS):
sudo iw dev wlan0 interface add wlan0_adhoc type ibss

# Alternatively, for 802.11s Mesh (recommended over legacy Ad-Hoc for stability):
# sudo iw dev wlan0 interface add wlan0_mesh type mesh

**4.Bring the virtual interfaces up:**Initialize interfaces before configuration.

Bash

sudo ip link set wlan0_ap up
sudo ip link set wlan0_adhoc up

Step 3: Configure Multiple Infrastructure SSIDs (hostapd)

To run multiple SSIDs on the infrastructure interface (wlan0_ap), hostapd supports virtual BSS (Multi-BSS). Create a configuration file named /etc/hostapd/multi_ssid.conf:

Ini, TOML

# Primary Interface & SSID
interface=wlan0_ap
driver=nl80211
ssid=Tactical-Primary-AP
hw_mode=g
channel=6
auth_algs=1
ignore_broadcast_ssid=0

# Virtual BSS #1 (Second simultaneous SSID on the same physical chip)
bss=wlan0_ap_guest
ssid=Tactical-Guest-Mesh
# Optional: isolate guest clients from primary network
ap_isolate=1

Note: If using multi-BSS via bss=, ensure you add the secondary virtual AP interface first:

Bash

sudo iw dev wlan0 interface add wlan0_ap_guest type __ap
sudo ip link set wlan0_ap_guest up

Start hostapd with your configuration:

Bash

sudo hostapd /etc/hostapd/multi_ssid.conf

Step 4: Configure the Ad-Hoc / Mesh Backbone

While your infrastructure SSIDs are broadcasting and serving clients on wlan0_ap, configure your second virtual interface (wlan0_adhoc) for peer-to-peer communication.

  1. Join the Ad-Hoc (IBSS) Network:

    Bash

    sudo iw dev wlan0_adhoc set type ibss
    sudo ip link set wlan0_adhoc up
    sudo iw dev wlan0_adhoc ibss join TacticalAdHocNet 2412 
    
    

    (Where TacticalAdHocNet is your shared ad-hoc SSID name and 2412 is channel 1 frequency in MHz).

  2. Assign IP Addresses & Routing:

    Bash

    sudo ip addr add 192.168.100.10/24 dev wlan0_adhoc
    
    

Step 5: Bridge Infrastructure and Ad-Hoc Traffic (SDN / BATMAN-adv Integration)

If you need traffic flowing between your infrastructure clients (connected to your AP SSIDs) and your ad-hoc mesh nodes, you must bridge or route packets across the interfaces.

  1. Enable IPv4 forwarding in the Linux kernel:

    Bash

    sudo sysctl -w net.ipv4.ip_forward=1
    
    
  2. If integrating with Layer 2 mesh routing protocols (such as BATMAN-adv matching your system architecture), bind the ad-hoc interface directly to the batman mesh interface:

    Bash

    sudo modprobe batman-adv
    sudo batctl -m bat0 if add wlan0_adhoc
    sudo ip link set dev bat0 up
    sudo ip addr add 10.0.0.10/24 dev bat0
    

To automate the creation of your virtual wireless interfaces (wlan0_ap and wlan0_adhoc) and ensure hostapd starts cleanly on system boot, you can use a custom initialization shell script combined with a systemd service unit.

Step 1: Create the Wireless Setup Script

Create an initialization script at /usr/local/bin/setup_tactical_wifi.sh. This script safely tears down any existing state, provisions the virtual interfaces, configures the ad-hoc network, and brings everything online.

Bash

#!/bin/bash
set -e

PHY="wlan0"
AP_IF="wlan0_ap"
ADHOC_IF="wlan0_adhoc"

echo "[*] Initializing tactical wireless virtual interfaces..."

# 1. Bring down physical radio to clear stale states
ip link set "$PHY" down 2>/dev/null || true

# 2. Clean up virtual interfaces if they already exist
iw dev "$AP_IF" del 2>/dev/null || true
iw dev "$ADHOC_IF" del 2>/dev/null || true

# 3. Create virtual interfaces
iw dev "$PHY" interface add "$AP_IF" type __ap
iw dev "$PHY" interface add "$ADHOC_IF" type ibss

# 4. Bring interfaces up
ip link set "$AP_IF" up
ip link set "$ADHOC_IF" up

# 5. Join Ad-Hoc (IBSS) network & assign IP
iw dev "$ADHOC_IF" set type ibss
iw dev "$ADHOC_IF" ibss join TacticalAdHocNet 2412
ip addr add 192.168.100.10/24 dev "$ADHOC_IF" 2>/dev/null || true

echo "[+] Virtual interfaces successfully provisioned."

Make the script executable:

Bash

sudo chmod +x /usr/local/bin/setup_tactical_wifi.sh

Step 2: Create the Systemd Service File

Create the systemd service file at /etc/systemd/system/tactical-wifi.service.

Using ExecStartPre, systemd will execute your setup script first. Once the virtual interfaces are fully instantiated and ready, ExecStart launches hostapd in the foreground to manage the infrastructure SSIDs.

Ini, TOML

[Unit]
Description=Tactical Multi-SSID Wireless Infrastructure & Mesh Service
After=network.target local-fs.target
Wants=network.target

[Service]
Type=simple
ExecStartPre=/usr/local/bin/setup_tactical_wifi.sh
ExecStart=/usr/sbin/hostapd /etc/hostapd/multi_ssid.conf
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

Step 3: Enable and Start the Service

Reload systemd to register the new service, enable it to start automatically on boot, and start it immediately:

Bash

# Reload systemd daemon
sudo systemctl daemon-reload

# Enable service on boot
sudo systemctl enable tactical-wifi.service

# Start the service now
sudo systemctl start tactical-wifi.service

Step 4: Verify Status and Logs

You can verify that the service started correctly and check real-time driver/hostapd output using journalctl:

Bash

sudo systemctl status tactical-wifi.service

To monitor live logs during startup or client association:

Bash

sudo journalctl -u tactical-wifi.service -f

To route and translate traffic between your infrastructure clients (connected to wlan0_ap) and your ad-hoc mesh backbone (wlan0_adhoc), you need to enable kernel packet forwarding and configure iptables NAT (Network Address Translation) and forwarding rules.

Here is how to update your initialization script to fully automate the bridge routing.

Updated Initialization Script (/usr/local/bin/setup_tactical_wifi.sh)

Replace your setup script with this expanded version, which provisions the interfaces, configures IP addresses, enables kernel forwarding, and applies the required iptables firewall/NAT rules:

Bash

#!/bin/bash
set -e

PHY="wlan0"
AP_IF="wlan0_ap"
ADHOC_IF="wlan0_adhoc"

echo "[*] Initializing tactical wireless virtual interfaces & routing..."

# 1. Bring down physical radio to clear stale states
ip link set "$PHY" down 2>/dev/null || true

# 2. Clean up virtual interfaces if they already exist
iw dev "$AP_IF" del 2>/dev/null || true
iw dev "$ADHOC_IF" del 2>/dev/null || true

# 3. Create virtual interfaces
iw dev "$PHY" interface add "$AP_IF" type __ap
iw dev "$PHY" interface add "$ADHOC_IF" type ibss

# 4. Bring interfaces up
ip link set "$AP_IF" up
ip link set "$ADHOC_IF" up

# 5. Configure IP addresses
ip addr add 192.168.10.1/24 dev "$AP_IF" 2>/dev/null || true     # AP Gateway IP for clients
ip addr add 192.168.100.10/24 dev "$ADHOC_IF" 2>/dev/null || true # Ad-hoc node IP

# 6. Join Ad-Hoc (IBSS) network
iw dev "$ADHOC_IF" set type ibss
iw dev "$ADHOC_IF" ibss join TacticalAdHocNet 2412

# 7. Enable Kernel IP Forwarding
sysctl -w net.ipv4.ip_forward=1

# 8. Configure iptables Rules for NAT and Forwarding
# Flush existing tactical rules to prevent duplication
iptables -D FORWARD -i "$AP_IF" -o "$ADHOC_IF" -j ACCEPT 2>/dev/null || true
iptables -D FORWARD -i "$ADHOC_IF" -o "$AP_IF" -j ACCEPT 2>/dev/null || true
iptables -t nat -D POSTROUTING -o "$ADHOC_IF" -j MASQUERADE 2>/dev/null || true

# Allow bidirectional forwarding between AP clients and Ad-hoc mesh
iptables -A FORWARD -i "$AP_IF" -o "$ADHOC_IF" -j ACCEPT
iptables -A FORWARD -i "$ADHOC_IF" -o "$AP_IF" -j ACCEPT

# Allow established/related traffic to flow back seamlessly
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# Enable NAT masquerading out through the ad-hoc mesh interface
iptables -t nat -A POSTROUTING -o "$ADHOC_IF" -j MASQUERADE

echo "[+] Virtual interfaces and NAT routing rules successfully applied."

Make sure the script has execution permissions:

Bash

sudo chmod +x /usr/local/bin/setup_tactical_wifi.sh

What Each Rule Accomplishes

  1. net.ipv4.ip_forward=1: Tells the Linux kernel to stop dropping packets arriving on one interface that are destined for another, allowing your node to act as an active router.

  2. FORWARD -i wlan0_ap -o wlan0_adhoc -j ACCEPT: Explicitly permits clients connected to your infrastructure Wi-Fi SSID to pass traffic into the ad-hoc mesh network.

  3. conntrack RELATED,ESTABLISHED: Ensures that return packets coming back from the mesh nodes can find their way back to the correct wireless client without getting blocked.

  4. POSTROUTING -o wlan0_adhoc -j MASQUERADE: Rewrites the source IP of packets leaving the AP subnet so they appear to originate from the routing node’s ad-hoc IP address (192.168.100.10), enabling seamless communication across remote mesh peers.

To provide automatic IP address assignment (DHCP) and name resolution (DNS) for clients connecting to your infrastructure AP (wlan0_ap), dnsmasq is the ideal lightweight service.

1

Install dnsmasq

Package Management

**1.Install dnsmasq:**Package Management.

Install the dnsmasq package via your package manager:

Bash

sudo apt update && sudo apt install -y dnsmasq

2

Stop default global service

Prerequisite

**2.Stop default global service:**Prerequisite.

Disable the default global dnsmasq service so it does not conflict with systemd-resolved on port 53:

Bash

sudo systemctl stop dnsmasq
sudo systemctl disable dnsmasq

3

Create a dedicated AP configuration file

/etc/dnsmasq.d/tactical_ap.conf

3.Create a dedicated AP configuration file:/etc/dnsmasq.d/tactical_ap.conf.

Create a custom configuration file to bind exclusively to your infrastructure AP interface (wlan0_ap) and establish the DHCP pool:

Ini, TOML

# Bind strictly to the AP interface
interface=wlan0_ap
bind-interfaces

# Define the DHCP IP pool and lease time (8 hours)
dhcp-range=192.168.10.50,192.168.10.150,255.255.255.0,8h

# Set the default gateway handed to clients
dhcp-option=3,192.168.10.1

# Provide DNS servers to clients (routing through gateway and upstream DNS)
dhcp-option=6,192.168.10.1,8.8.8.8

# Assign local domain scope
domain=tactical.local

4

Enable and start dnsmasq

Service Activation

**4.Enable and start dnsmasq:**Service Activation.

Start the service and verify its status:

Bash

sudo systemctl enable dnsmasq
sudo systemctl restart dnsmasq

Verification

Once wireless clients associate with your infrastructure SSID, you can inspect active IP assignments and leases in real-time with:

Bash

cat /var/lib/misc/dnsmasq.leases

To implement domain blacklisting (blocking unwanted domains, telemetry, or threat vectors) and custom DNS redirection (routing specific domains to designated local nameservers) in dnsmasq, you can add specific directives directly to your configuration file.

Step 1: Update the Dnsmasq Configuration

Append your blacklisting and custom redirection rules to your existing AP configuration file at /etc/dnsmasq.d/tactical_ap.conf:

Ini, TOML

# ==========================================
# 1. CORE AP & DHCP SETTINGS (Existing)
# ==========================================
interface=wlan0_ap
bind-interfaces
dhcp-range=192.168.10.50,192.168.10.150,255.255.255.0,8h
dhcp-option=3,192.168.10.1
dhcp-option=6,192.168.10.1,8.8.8.8
domain=tactical.local

# ==========================================
# 2. DOMAIN BLACKLISTING (Ad/Malware Blocking)
# ==========================================
# Directs unwanted or malicious domains to a null IP (0.0.0.0)
address=/ads.exampletracker.com/0.0.0.0
address=/telemetry.badactor.net/0.0.0.0

# Alternatively, return NXDOMAIN (Domain does not exist) instantly:
# address=/unwanted-domain.com/

# ==========================================
# 3. CUSTOM DNS REDIRECTION & SPLIT-DNS
# ==========================================
# Force specific local or mesh domains to resolve via a dedicated internal nameserver
server=/mesh.internal/192.168.100.1
server=/tactical.node/192.168.100.15

# Force a specific public domain to use a custom upstream resolver
server=/trusted-service.org/1.1.1.1

Step 2: Apply and Restart Dnsmasq

After saving the configuration changes, validate the syntax and restart the service to apply the rules:

Bash

# Test configuration syntax for errors
sudo dnsmasq --test

# Restart dnsmasq to load new rules
sudo systemctl restart dnsmasq

Step 3: Verify Rules Work

You can test both blacklisting and custom resolution from a client connected to your network (or directly on the host) using dig or nslookup:

  1. Test Blacklisting:

    Bash

    dig ads.exampletracker.com @192.168.10.1
    
    

    Expected Result: The returned IP address will resolve to 0.0.0.0.

  2. Test Custom Redirection:

    Bash

    dig node-alpha.mesh.internal @192.168.10.1
    
    

    Expected Result: The query will be silently forwarded to your internal nameserver (192.168.100.1) and resolve to its correct mesh address.

Create the Automated Ingestion Script

Execution script placed at /usr/local/bin/update_dns_blocklist.sh

**1.Create the Automated Ingestion Script:**Execution script placed at /usr/local/bin/update_dns_blocklist.sh.

Create a script that securely downloads a standard threat intelligence hosts file, parses it into dnsmasq-compatible address=/domain/0.0.0.0 syntax, validates the configuration, and reloads the service automatically:

Bash

sudo tee /usr/local/bin/update_dns_blocklist.sh > /dev/null << 'EOF'
#!/bin/bash
set -e

# Example feed: StevenBlack unified hosts or specialized threat Intel feeds
BLOCKLIST_URL="https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"
OUTPUT_FILE="/etc/dnsmasq.d/threat_blocklist.conf"
TEMP_FILE="/tmp/dnsmasq_blocklist_raw.tmp"

echo "[*] Downloading latest threat intelligence blocklist..."
curl -sSL "$BLOCKLIST_URL" -o "$TEMP_FILE"

echo "[*] Parsing and formatting blocklist for dnsmasq..."
# Convert 0.0.0.0/127.0.0.1 entries into dnsmasq address rules, excluding local loopback
awk '/^0\.0\.0\.0|^127\.0\.0\.1/ {
    if ($2 != "localhost" && $2 != "local" && $2 != "" && $2 !~ /#/) {
        print "address=/" $2 "/0.0.0.0"
    }
}' "$TEMP_FILE" > "$OUTPUT_FILE"

rm -f "$TEMP_FILE"

echo "[*] Verifying dnsmasq configuration syntax..."
if dnsmasq --test; then
    echo "[+] Syntax valid. Reloading dnsmasq service..."
    systemctl reload dnsmasq
    echo "[+] Threat intelligence blocklist imported successfully."
else
    echo "[-] ERROR: dnsmasq syntax validation failed! Removing malformed blocklist."
    rm -f "$OUTPUT_FILE"
    systemctl reload dnsmasq
    exit 1
fi
EOF

sudo chmod +x /usr/local/bin/update_dns_blocklist.sh

Verification: Run ls -l /usr/local/bin/update_dns_blocklist.sh to confirm the script exists and has execute permissions.

2

Run Initial Import Test

Manual execution and syntax check

**2.Run Initial Import Test:**Manual execution and syntax check.

Execute the script manually to generate the initial blocklist file and load it into dnsmasq:

Bash

sudo /usr/local/bin/update_dns_blocklist.sh

Verification: Check that /etc/dnsmasq.d/threat_blocklist.conf was populated with thousands of filtered blocklist entries and that sudo systemctl status dnsmasq reports an active, running state.

3

Automate Periodic Updates via Cron

Scheduling regular updates

**3.Automate Periodic Updates via Cron:**Scheduling regular updates.

To keep threat intelligence feeds fresh, automate daily or weekly updates using a cron job. Open the root crontab:

Bash

sudo crontab -e

Add the following entry to run the update script every Sunday at 3:00 AM:

cron

0 3 * * 0 /usr/local/bin/update_dns_blocklist.sh >> /var/log/dns_blocklist_update.log 2>&1

Verification: Check active cron jobs with sudo crontab -l to ensure the schedule is registered.

Verification of Blocked Resolution

Test that the imported blocklist successfully intercepts queries on your network:

Bash

dig malware-example-domain.com @192.168.10.1

Expected Result: The query returns an immediate response pointing to 0.0.0.0.

To track and audit blocked domain attempts, you can enable dnsmasq query logging and route them to a dedicated log file. This allows you to monitor exactly which clients are attempting to query blocked threat intelligence domains in real time.

**1.Enable Query Logging and Dedicated File:**Configuration Update at /etc/dnsmasq.d/tactical_ap.conf.

Add the log-queries directive and specify a dedicated log facility so DNS requests don’t clutter standard system logs:

Ini, TOML

# Enable detailed logging of all DNS queries handled by dnsmasq
log-queries

# Route dnsmasq logs to a dedicated file instead of general syslog
log-facility=/var/log/dnsmasq.log

Apply the configuration changes by restarting the service:

Bash

sudo systemctl restart dnsmasq

**2.Configure Log Rotation:**Prevent Disk Exhaustion via Logrotate.

Because DNS traffic can generate large logs quickly, configure logrotate to automatically compress and archive the log file daily. Create /etc/logrotate.d/dnsmasq_tactical:

Bash

sudo tee /etc/logrotate.d/dnsmasq_tactical > /dev/null << 'EOF'
/var/log/dnsmasq.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 640 root adm
    sharedscripts
    postrotate
        systemctl reload dnsmasq > /dev/null 2>&1 || true
    endscript
}
EOF

Verification: Run sudo logrotate -d /etc/logrotate.d/dnsmasq_tactical to test the configuration syntax.

**3.Monitor Blocked Domain Attempts:**Real-time filtering using tail and grep.

Since blocked domains resolve to 0.0.0.0 based on your threat intelligence lists, you can filter the live log to watch blocked requests in real time:

Bash

tail -f /var/log/dnsmasq.log | grep "is 0.0.0.0"

Verification: From a connected client, try querying a known blocked domain (e.g., dig ads.exampletracker.com @192.168.10.1) and confirm the attempt instantly appears in your filtered log output with its client IP source.