Skip to content

Instantly share code, notes, and snippets.

@eznix86
Created June 11, 2025 20:30
Show Gist options
  • Save eznix86/4b562aeafd99a0ad4479bba13e6dee31 to your computer and use it in GitHub Desktop.
Save eznix86/4b562aeafd99a0ad4479bba13e6dee31 to your computer and use it in GitHub Desktop.
#!/bin/bash
set -e
if [[ $EUID -ne 0 ]]; then
echo "[ERROR] This script must be run as root (use sudo)." >&2
exit 1
fi
SUBNET="192.168.42."
echo "[INFO] Detecting host IP in subnet $SUBNET using arp -a..."
HOST_IP=$(arp -a | grep "$SUBNET" | awk '{print $2}' | tr -d '()' | head -n1)
if [[ -z "$HOST_IP" ]]; then
echo "[ERROR] Could not find host IP in subnet $SUBNET." >&2
exit 1
fi
echo "[INFO] Host IP detected as $HOST_IP"
echo "[INFO] SSH into host ($HOST_IP) to enable IP forwarding and iptables rules..."
ssh root@"$HOST_IP" bash -s <<EOF
set -e
echo "[HOST] Enabling IP forwarding..."
sysctl -w net.ipv4.ip_forward=1 >/dev/null
if [[ \$(sysctl -n net.ipv4.ip_forward) -ne 1 ]]; then
echo "[HOST ERROR] Failed to enable IP forwarding." >&2
exit 1
fi
OUT_IF=\$(ip route get 8.8.8.8 2>/dev/null | awk '{print \$5; exit}')
if [[ -z "\$OUT_IF" ]]; then
echo "[HOST ERROR] Could not detect outgoing interface." >&2
exit 1
fi
echo "[HOST] Outgoing interface detected: \$OUT_IF"
echo "[HOST] Setting iptables rules..."
iptables -P FORWARD ACCEPT
iptables -t nat -C POSTROUTING -s 192.168.42.0/24 -o "\$OUT_IF" -j MASQUERADE 2>/dev/null \
|| iptables -t nat -A POSTROUTING -s 192.168.42.0/24 -o "\$OUT_IF" -j MASQUERADE
if ! iptables -t nat -L POSTROUTING -n | grep -q MASQUERADE; then
echo "[HOST ERROR] iptables MASQUERADE rule was not set correctly." >&2
exit 1
fi
echo "[HOST] IP forwarding and NAT setup complete."
EOF
echo "[INFO] Setting default route on Milk-V Duo to host $HOST_IP..."
ip route replace default via "$HOST_IP"
echo "[INFO] Setting DNS on Milk-V Duo..."
echo "nameserver 8.8.8.8" >> /etc/resolv.conf
echo "[INFO] Testing connectivity from Milk-V Duo..."
if ping -c 2 -W 2 8.8.8.8 >/dev/null; then
echo "[SUCCESS] Milk-V Duo can reach 8.8.8.8"
if ping -c 2 -W 2 google.com >/dev/null; then
echo "[SUCCESS] DNS resolution works (google.com reachable)"
else
echo "[WARNING] DNS resolution failed, but IP connectivity works."
fi
else
echo "[ERROR] Milk-V Duo cannot reach the internet via host." >&2
exit 1
fi
@eznix86
Copy link
Author

eznix86 commented Jun 11, 2025

Do it on boot

This only applies for alpine version

You can also set the static ip by looking at, but it is different.

https://xyzdims.com/3d-printers/misc-hardware-notes/iot-milk-v-duo-risc-v-esbc-running-linux/#Static_IP_for_Host_with_RNDIS

Setup Mac address

create /opt/milkv/rndis-macs.sh and do chmod +x /opt/milkv/rndis-macs.sh

#!/bin/bash

RNDIS_USB="/tmp/usb/usb_gadget/cvitek/functions/rndis.usb0"
MAC_FILE="/etc/rndis-macs.conf"

generate_random_mac() {
    printf "02:%02x:%02x:%02x:%02x:%02x\n" $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256))
}

# check if the MAC address file exists and has exactly two lines
if [[ -f "$MAC_FILE" ]] && [[ $(wc -l < "$MAC_FILE") -eq 2 ]]; then
    # read the two MAC addresses from the file
    IFS=$'\n' read -d '' -r -a macs < "$MAC_FILE"
    dev="${macs[0]}"
    host="${macs[1]}"
    echo "using existing MAC addresses:"
else
    # generate two new MAC addresses and store them in the file
    echo "generating new MAC addresses:"
    dev=$(generate_random_mac)
    host=$(generate_random_mac)
    echo "$dev" > "$MAC_FILE"
    echo "$host" >> "$MAC_FILE"
fi
echo "dev_addr: $dev"
echo "host_addr: $host"
echo "$dev" > "$RNDIS_USB"/dev_addr
echo "$host" > "$RNDIS_USB"/host_addr

Afterwards

Edit /etc/init.d/usb-rndis it should be like this

#!/sbin/openrc-run

start() {
        /opt/milkv/uhubon.sh device
        /opt/milkv/run_usb.sh probe rndis
        /opt/milkv/rndis-macs.sh
        /opt/milkv/run_usb.sh start rndis

        sleep 0.5

        ip addr add 192.168.42.1/24 dev usb0
        ip link set usb0 up
        ip route add default via 192.168.42.2

        sleep 0.5
        count=`ps | grep dnsmasq | grep -v grep | wc -l`
        if [ ${count} -lt 1 ] ;then
          rc-service dnsmasq start
        fi
}

stop () {
        rc-service dnsmasq stop
        ifconfig usb0 down
        /opt/milkv/run_usb.sh stop rndis
}

Edit /etc/dnsmasq.conf so it looks like this

interface=usb0
dhcp-range=192.168.42.2,192.168.42.2,1h
dhcp-option=3
dhcp-option=6

Now to automatically setup internet on boot:

tee /usr/local/bin/milkv-network-setup.sh > /dev/null <<'EOF'
#!/bin/sh

set -e

if [ "$(id -u)" != "0" ]; then
  echo "[ERROR] Must be run as root." >&2
  exit 1
fi

SUBNET="192.168.42."

echo "[INFO] Detecting host IP in subnet $SUBNET using arp -a..."
HOST_IP=$(arp -a | grep "$SUBNET" | awk '{print $2}' | tr -d '()' | head -n1)

if [ -z "$HOST_IP" ]; then
  echo "[ERROR] Could not find host IP in subnet $SUBNET." >&2
  exit 1
fi

echo "[INFO] Host IP detected as $HOST_IP"

echo "[INFO] SSH into host ($HOST_IP) to enable IP forwarding and iptables rules..."
ssh root@"$HOST_IP" sh -s <<EOF2
  set -e
  echo "[HOST] Enabling IP forwarding..."
  sysctl -w net.ipv4.ip_forward=1 >/dev/null

  OUT_IF=\$(ip route get 8.8.8.8 2>/dev/null | awk '{print \$5; exit}')
  if [ -z "\$OUT_IF" ]; then
    echo "[HOST ERROR] Could not detect outgoing interface." >&2
    exit 1
  fi
  echo "[HOST] Outgoing interface detected: \$OUT_IF"

  iptables -P FORWARD ACCEPT
  iptables -t nat -C POSTROUTING -s 192.168.42.0/24 -o "\$OUT_IF" -j MASQUERADE 2>/dev/null || \
  iptables -t nat -A POSTROUTING -s 192.168.42.0/24 -o "\$OUT_IF" -j MASQUERADE

  if ! iptables -t nat -L POSTROUTING -n | grep -q MASQUERADE; then
    echo "[HOST ERROR] iptables MASQUERADE rule was not set correctly." >&2
    exit 1
  fi
  echo "[HOST] IP forwarding and NAT setup complete."
EOF2

echo "[INFO] Setting default route on Milk-V Duo to host $HOST_IP..."
ip route replace default via "$HOST_IP"

echo "[INFO] Setting DNS on Milk-V Duo..."
echo "nameserver 8.8.8.8" >> /etc/resolv.conf

echo "[INFO] Testing connectivity from Milk-V Duo..."

if ping -c 2 -W 2 8.8.8.8 >/dev/null; then
  echo "[SUCCESS] Milk-V Duo can reach 8.8.8.8"
  if ping -c 2 -W 2 google.com >/dev/null; then
    echo "[SUCCESS] DNS resolution works (google.com reachable)"
  else
    echo "[WARNING] DNS resolution failed, but IP connectivity works."
  fi
else
  echo "[ERROR] Milk-V Duo cannot reach the internet via host." >&2
  exit 1
fi
EOF

chmod +x /usr/local/bin/milkv-network-setup.sh

Things to do before:

  • run ssh-keygen without a password on the milkv-duo
  • copy the public key and place it inside of the host authorized_keys (for the root)
  • ensure that iptables is setup correctly.
  • run /usr/local/bin/milkv-network-setup.sh to know if it is working correctly

2. Create an OpenRC service

Create a file /etc/init.d/milkv-network-setup:

tee /etc/init.d/milkv-network-setup > /dev/null <<'EOF'
#!/sbin/openrc-run

description="Milk-V Duo network setup to configure routing via host"

depend() {
    need net
    after firewall
}

start() {
    ebegin "Running Milk-V network setup"
    /usr/local/bin/milkv-network-setup.sh
    eend $?
}
EOF

chmod +x /etc/init.d/milkv-network-setup

3. Enable the service

rc-update add milkv-network-setup default

4. Test it now (optional)

rc-service milkv-network-setup start

Ensure that the host recognize the milkv-duo via ssh

Example doing ssh-keygen and add the public key to the root

How it works

  • The script runs after network is up.
  • It sets routing/DNS and configures the host remotely over SSH.
  • On reboot, it will automatically run your network setup.

if the hosts reboots:

follow this: https://gist.github.com/eznix86/26f1547fcbfb7a0e599c08b72463fc62

@eznix86
Copy link
Author

eznix86 commented Jun 11, 2025

if time is an issue append the script with:

echo "Syncing time with NTP..."
ntpd -d -q -n -p pool.ntp.org
echo "Time sync completed"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment