summaryrefslogtreecommitdiff
path: root/test-env/net-sim
diff options
context:
space:
mode:
Diffstat (limited to 'test-env/net-sim')
-rwxr-xr-xtest-env/net-sim/netsim.sh489
1 files changed, 489 insertions, 0 deletions
diff --git a/test-env/net-sim/netsim.sh b/test-env/net-sim/netsim.sh
new file mode 100755
index 0000000..8b0f68e
--- /dev/null
+++ b/test-env/net-sim/netsim.sh
@@ -0,0 +1,489 @@
+#!/bin/bash
+#
+# Network Simulator for Hoods Gate Testing
+# Isolated network environment with fake internet responses
+#
+
+# Configuration
+STATE_DIR="/tmp/netsim"
+STATE_FILE="${STATE_DIR}/state"
+NETNS_CLIENT="netsim_client"
+NETNS_EXIT="netsim_exit"
+NETNS_INTERNET="netsim_internet"
+
+# Network Configuration
+BRIDGE_CLIENT="br-client"
+BRIDGE_EXIT="br-exit"
+BRIDGE_WAN="br-wan" # Bridge for WAN side connection
+VETH_CLIENT_HOST="veth-c-host"
+VETH_CLIENT_NS="veth-c-ns"
+VETH_EXIT_HOST="veth-e-host"
+VETH_EXIT_NS="veth-e-ns"
+VETH_INET_EXIT="veth-i-exit"
+VETH_INET_NS="veth-i-ns"
+EXIT_WAN_IFACE="wan0" # Interface name inside exit KVM
+
+# IP Configuration
+IP_CLIENT_BRIDGE="10.10.1.1/24"
+IP_CLIENT_VM="10.10.1.10/24"
+IP_EXIT_BRIDGE="10.10.2.1/24"
+IP_EXIT_VM="10.10.2.10/24"
+IP_EXIT_WAN="203.0.113.10/24" # WAN IP for exit node
+IP_INET_GATEWAY="203.0.113.1/24" # Gateway in internet namespace
+
+RED=$'\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+BLUE='\033[0;34m'
+NC=$'\033[0m'
+
+check_root() {
+ if [ "$EUID" -ne 0 ]; then
+ echo -e "${RED}Error: This script must be run as root${NC}"
+ exit 1
+ fi
+}
+
+fail() {
+ echo -e "${RED}$2${NC}" >&2
+ exit $1
+}
+
+usage() {
+ cat << EOF
+ ▄▄▄ ▄▄ ██
+ ███ ██ ██ ▀▀
+ ██▀█ ██ ▄████▄ ███████ ▄▄█████▄ ████ ████▄██▄
+ ██ ██ ██ ██▄▄▄▄██ ██ ██▄▄▄▄ ▀ ██ ██ ██ ██
+ ██ █▄██ ██▀▀▀▀▀▀ ██ ▀▀▀▀██▄ ██ ██ ██ ██
+ ██ ███ ▀██▄▄▄▄█ ██▄▄▄ █▄▄▄▄▄██ ▄▄▄██▄▄▄ ██ ██ ██
+ ▀▀ ▀▀▀ ▀▀▀▀▀ ▀▀▀▀ ▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀ ▀▀ ▀▀ ▀▀
+*Network Simulator for Hoods Gate Testing${NC}
+
+Usage:
+ $0 setup [bandwidth] [latency]
+ Create network topology for Hoods Gate testing
+ bandwidth: in mbit (default: 100)
+ latency: in ms (default: 10)
+ Example: $0 setup 50 20
+
+ $0 status
+ Show current network configuration and statistics
+
+ $0 logs
+ Show traffic logs from fake internet
+
+ $0 adjust <bandwidth> <latency>
+ Adjust network conditions on the fly
+ Example: $0 adjust 10 100
+
+ $0 teardown
+ Remove all network configuration
+
+ $0 test
+ Run connectivity tests
+
+Network Topology Created:
+ [Client KVM] ---> [Bridge] ---> [Exit KVM] ---> [Fake Internet]
+ 10.10.1.10 10.10.1.1 10.10.2.10 192.168.100.2
+
+Instructions for KVMs:
+ Client KVM: Attach to bridge '${BRIDGE_CLIENT}', use IP 10.10.1.10/24, gateway 10.10.1.1
+ Exit KVM: Attach to bridge '${BRIDGE_EXIT}', use IP 10.10.2.10/24, gateway 10.10.2.1
+ SDN should route traffic to 192.168.100.1
+
+EOF
+ exit 0
+}
+
+init_state() {
+ mkdir -p "${STATE_DIR}"
+ touch "${STATE_FILE}"
+}
+
+# Setup network topology
+setup_network() {
+ local bandwidth=${1:-100}
+ local latency=${2:-10}
+
+ echo -e "${GREEN}Setting up network simulation...${NC}"
+
+ # Clean up any existing setup
+ teardown_network 2>/dev/null
+
+ echo -e "${BLUE}[1/7]${NC} Creating network namespaces..."
+ ip netns add ${NETNS_EXIT} 2>/dev/null
+ ip netns add ${NETNS_INTERNET} 2>/dev/null
+
+ echo -e "${BLUE}[2/7]${NC} Creating bridges for KVM attachment..."
+ ip link add ${BRIDGE_CLIENT} type bridge
+ ip link add ${BRIDGE_EXIT} type bridge
+ ip link add ${BRIDGE_WAN} type bridge
+ ip addr add ${IP_CLIENT_BRIDGE} dev ${BRIDGE_CLIENT}
+ ip addr add ${IP_EXIT_BRIDGE} dev ${BRIDGE_EXIT}
+ ip link set ${BRIDGE_CLIENT} up
+ ip link set ${BRIDGE_EXIT} up
+ ip link set ${BRIDGE_WAN} up
+
+ echo -e "${BLUE}[3/7]${NC} Creating veth pairs..."
+ # Exit namespace LAN side connection
+ ip link add ${VETH_EXIT_HOST} type veth peer name ${VETH_EXIT_NS}
+ ip link set ${VETH_EXIT_NS} netns ${NETNS_EXIT}
+ ip link set ${VETH_EXIT_HOST} master ${BRIDGE_EXIT}
+ ip link set ${VETH_EXIT_HOST} up
+
+ # WAN bridge to internet namespace connection
+ ip link add veth-wan-br type veth peer name veth-wan-inet
+ ip link set veth-wan-br master ${BRIDGE_WAN}
+ ip link set veth-wan-inet netns ${NETNS_INTERNET}
+ ip link set veth-wan-br up
+
+ # Internet namespace connection
+ ip link add ${VETH_INET_EXIT} type veth peer name ${VETH_INET_NS}
+ ip link set ${VETH_INET_EXIT} master ${BRIDGE_WAN}
+ ip link set ${VETH_INET_NS} netns ${NETNS_INTERNET}
+ ip link set ${VETH_INET_EXIT} up
+
+ echo -e "${BLUE}[4/7]${NC} Configuring IP addresses..."
+ # Exit namespace LAN IP only (no WAN IP - that's on the KVM side)
+ ip netns exec ${NETNS_EXIT} ip addr add ${IP_EXIT_BRIDGE} dev ${VETH_EXIT_NS}
+ ip netns exec ${NETNS_EXIT} ip link set ${VETH_EXIT_NS} up
+ ip netns exec ${NETNS_EXIT} ip link set lo up
+
+ # Internet namespace IPs (acts as the gateway)
+ ip netns exec ${NETNS_INTERNET} ip addr add ${IP_INET_GATEWAY} dev veth-wan-inet
+ ip netns exec ${NETNS_INTERNET} ip addr add 8.8.8.8/32 dev lo # Fake DNS server
+ ip netns exec ${NETNS_INTERNET} ip addr add 1.1.1.1/32 dev lo # Fake DNS server
+ ip netns exec ${NETNS_INTERNET} ip link set veth-wan-inet up
+ ip netns exec ${NETNS_INTERNET} ip link set ${VETH_INET_NS} up
+ ip netns exec ${NETNS_INTERNET} ip link set lo up
+
+ echo -e "${BLUE}[5/7]${NC} Configuring routing..."
+ # Host routing for client bridge - NAT to exit bridge
+ iptables -t nat -A POSTROUTING -s 10.10.1.0/24 -o ${BRIDGE_EXIT} -j MASQUERADE
+ echo 1 > /proc/sys/net/ipv4/ip_forward
+
+ # Internet namespace routing (responds to everything, blackholes it)
+ ip netns exec ${NETNS_INTERNET} sysctl -w net.ipv4.ip_forward=1 >/dev/null
+ ip netns exec ${NETNS_INTERNET} ip route add default dev veth-wan-inet
+
+ # Note: Exit KVM will handle routing from LAN to WAN interface
+
+ echo -e "${BLUE}[6/7]${NC} Applying traffic control (${bandwidth}mbit, ${latency}ms)..."
+ apply_tc ${bandwidth} ${latency}
+
+ echo -e "${BLUE}[7/7]${NC} Starting fake internet services..."
+ start_fake_internet
+
+ # Save configuration
+ echo "bandwidth=${bandwidth}" > "${STATE_FILE}"
+ echo "latency=${latency}" >> "${STATE_FILE}"
+ echo "timestamp=$(date +%s)" >> "${STATE_FILE}"
+
+ echo -e "${GREEN}✓ Network simulation setup complete!${NC}"
+ echo ""
+ echo -e "${YELLOW}Next steps:${NC}"
+ echo " 1. Attach Client KVM to bridge: ${BRIDGE_CLIENT}"
+ echo " Configure with IP: 10.10.1.10/24, Gateway: 10.10.1.1, DNS: 10.10.1.1"
+ echo ""
+ echo " 2. Attach Exit KVM with TWO network interfaces:"
+ echo " - LAN interface to bridge: ${BRIDGE_EXIT}"
+ echo " Configure with IP: 10.10.2.10/24"
+ echo " - WAN interface to bridge: ${BRIDGE_WAN}"
+ echo " This will appear as '${EXIT_WAN_IFACE}' inside the VM"
+ echo " Configure with IP: 203.0.113.10/24, Gateway: 203.0.113.1"
+ echo ""
+ echo " 3. SDN should route traffic OUT of the '${EXIT_WAN_IFACE}' interface"
+ echo " (Just like routing out eth0 on a normal machine)"
+ echo ""
+ echo " 4. Run '$0 test' to verify connectivity"
+}
+
+# Apply traffic control
+apply_tc() {
+ local bandwidth=$1
+ local latency=$2
+
+ # Apply to client->exit connection
+ tc qdisc del dev ${VETH_EXIT_HOST} root 2>/dev/null
+ tc qdisc add dev ${VETH_EXIT_HOST} root handle 1: htb default 10
+ tc class add dev ${VETH_EXIT_HOST} parent 1: classid 1:10 htb rate ${bandwidth}mbit
+ tc qdisc add dev ${VETH_EXIT_HOST} parent 1:10 handle 10: netem delay ${latency}ms
+
+ # Apply to WAN bridge (exit->internet)
+ tc qdisc del dev ${VETH_INET_EXIT} root 2>/dev/null
+ tc qdisc add dev ${VETH_INET_EXIT} root handle 1: htb default 10
+ tc class add dev ${VETH_INET_EXIT} parent 1: classid 1:10 htb rate ${bandwidth}mbit
+ tc qdisc add dev ${VETH_INET_EXIT} parent 1:10 handle 10: netem delay ${latency}ms
+}
+
+# Start fake internet services
+start_fake_internet() {
+ local log_file="${STATE_DIR}/traffic.log"
+ > "${log_file}"
+
+ # DNS Server (responds with fake IPs)
+ ip netns exec ${NETNS_INTERNET} dnsmasq \
+ --no-daemon \
+ --listen-address=${IP_INET_GATEWAY%/*} \
+ --address=/#/93.184.216.34 \
+ --log-queries \
+ --log-facility=${STATE_DIR}/dns.log \
+ --no-resolv \
+ --no-poll \
+ >/dev/null 2>&1 &
+ echo $! > "${STATE_DIR}/dns.pid"
+
+ # HTTP/HTTPS responder
+ ip netns exec ${NETNS_INTERNET} python3 -c "
+import socket
+import threading
+import datetime
+
+def log_request(proto, ip, port, data):
+ with open('${log_file}', 'a') as f:
+ f.write(f'{datetime.datetime.now()} | {proto} | {ip}:{port} | {len(data)} bytes\\n')
+
+def http_server():
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ sock.bind(('0.0.0.0', 80))
+ sock.listen(5)
+ while True:
+ try:
+ conn, addr = sock.accept()
+ data = conn.recv(4096)
+ log_request('HTTP', addr[0], addr[1], data)
+ response = b'HTTP/1.1 200 OK\\r\\nContent-Type: text/html\\r\\n\\r\\n<html><body><h1>Fake Internet Response</h1></body></html>'
+ conn.sendall(response)
+ conn.close()
+ except: pass
+
+def https_server():
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ sock.bind(('0.0.0.0', 443))
+ sock.listen(5)
+ while True:
+ try:
+ conn, addr = sock.accept()
+ data = conn.recv(4096)
+ log_request('HTTPS', addr[0], addr[1], data)
+ conn.close()
+ except: pass
+
+def generic_tcp():
+ for port in [22, 21, 25, 3389, 3306, 5432, 6379]:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ try:
+ sock.bind(('0.0.0.0', port))
+ sock.listen(1)
+ threading.Thread(target=lambda s=sock, p=port: tcp_handler(s, p), daemon=True).start()
+ except: pass
+
+def tcp_handler(sock, port):
+ while True:
+ try:
+ conn, addr = sock.accept()
+ data = conn.recv(4096)
+ log_request(f'TCP/{port}', addr[0], addr[1], data)
+ conn.close()
+ except: pass
+
+threading.Thread(target=http_server, daemon=True).start()
+threading.Thread(target=https_server, daemon=True).start()
+threading.Thread(target=generic_tcp, daemon=True).start()
+
+import time
+while True: time.sleep(1)
+" >/dev/null 2>&1 &
+ echo $! > "${STATE_DIR}/http.pid"
+
+ # ICMP responder (respond to pings)
+ ip netns exec ${NETNS_INTERNET} bash -c "
+ while true; do
+ ping -c 1 8.8.8.8 >/dev/null 2>&1 || true
+ sleep 1
+ done
+ " >/dev/null 2>&1 &
+ echo $! > "${STATE_DIR}/icmp.pid"
+}
+
+# Show status
+show_status() {
+ if [ ! -f "${STATE_FILE}" ]; then
+ echo -e "${YELLOW}No simulation running${NC}"
+ return
+ fi
+
+ source "${STATE_FILE}"
+
+ echo -e "${GREEN}Network Simulation Status${NC}"
+ echo "================================"
+ echo -e "Bandwidth: ${bandwidth}mbit"
+ echo -e "Latency: ${latency}ms"
+ echo -e "Running since: $(date -d @${timestamp})"
+ echo ""
+
+ echo -e "${GREEN}Network Namespaces:${NC}"
+ ip netns list | grep netsim && echo -e "${GREEN}✓${NC} Namespaces active" || echo -e "${RED}✗${NC} Namespaces missing"
+ echo ""
+
+ echo -e "${GREEN}Bridges (for KVM attachment):${NC}"
+ ip link show ${BRIDGE_CLIENT} >/dev/null 2>&1 && echo -e "${GREEN}✓${NC} ${BRIDGE_CLIENT} - Client KVM (LAN side)" || echo -e "${RED}✗${NC} ${BRIDGE_CLIENT} missing"
+ ip link show ${BRIDGE_EXIT} >/dev/null 2>&1 && echo -e "${GREEN}✓${NC} ${BRIDGE_EXIT} - Exit KVM (LAN side)" || echo -e "${RED}✗${NC} ${BRIDGE_EXIT} missing"
+ ip link show ${BRIDGE_WAN} >/dev/null 2>&1 && echo -e "${GREEN}✓${NC} ${BRIDGE_WAN} - Exit KVM (WAN side)" || echo -e "${RED}✗${NC} ${BRIDGE_WAN} missing"
+ echo ""
+
+ echo -e "${GREEN}Fake Internet Services:${NC}"
+ [ -f "${STATE_DIR}/dns.pid" ] && kill -0 $(cat "${STATE_DIR}/dns.pid") 2>/dev/null && echo -e "${GREEN}✓${NC} DNS (port 53)" || echo -e "${RED}✗${NC} DNS not running"
+ [ -f "${STATE_DIR}/http.pid" ] && kill -0 $(cat "${STATE_DIR}/http.pid") 2>/dev/null && echo -e "${GREEN}✓${NC} HTTP/HTTPS (ports 80, 443)" || echo -e "${RED}✗${NC} HTTP not running"
+ echo ""
+
+ echo -e "${GREEN}Traffic Statistics:${NC}"
+ if [ -f "${STATE_DIR}/traffic.log" ]; then
+ local total=$(wc -l < "${STATE_DIR}/traffic.log")
+ echo " Total requests: ${total}"
+ if [ ${total} -gt 0 ]; then
+ echo " Last 5 requests:"
+ tail -5 "${STATE_DIR}/traffic.log" | sed 's/^/ /'
+ fi
+ else
+ echo " No traffic logged yet"
+ fi
+}
+
+# Show logs
+show_logs() {
+ echo -e "${GREEN}Traffic Logs${NC}"
+ echo "================================"
+
+ if [ -f "${STATE_DIR}/traffic.log" ]; then
+ cat "${STATE_DIR}/traffic.log"
+ else
+ echo "No traffic logged"
+ fi
+
+ echo ""
+ echo -e "${GREEN}DNS Queries${NC}"
+ echo "================================"
+
+ if [ -f "${STATE_DIR}/dns.log" ]; then
+ tail -20 "${STATE_DIR}/dns.log"
+ else
+ echo "No DNS queries logged"
+ fi
+}
+
+# Adjust network conditions
+adjust_network() {
+ local bandwidth=$1
+ local latency=$2
+
+ if [ -z "$bandwidth" ] || [ -z "$latency" ]; then
+ fail 1 "Usage: $0 adjust <bandwidth> <latency>"
+ fi
+
+ echo -e "${GREEN}Adjusting network conditions...${NC}"
+ echo " Bandwidth: ${bandwidth}mbit"
+ echo " Latency: ${latency}ms"
+
+ apply_tc ${bandwidth} ${latency}
+
+ # Update state file
+ sed -i "s/^bandwidth=.*/bandwidth=${bandwidth}/" "${STATE_FILE}"
+ sed -i "s/^latency=.*/latency=${latency}/" "${STATE_FILE}"
+
+ echo -e "${GREEN}✓ Network conditions updated${NC}"
+}
+
+# Run connectivity tests
+run_tests() {
+ echo -e "${GREEN}Running connectivity tests...${NC}"
+ echo ""
+
+ echo -e "${BLUE}Test 1: Ping fake internet gateway${NC}"
+ ping -c 3 ${IP_INET_GATEWAY%/*} 2>/dev/null && \
+ echo -e "${GREEN}✓ PASS${NC}" || echo -e "${RED}✗ FAIL${NC}"
+ echo ""
+
+ echo -e "${BLUE}Test 2: HTTP request to fake internet${NC}"
+ ip netns exec ${NETNS_INTERNET} timeout 5 python3 -m http.server 8080 >/dev/null 2>&1 &
+ local pid=$!
+ sleep 1
+ curl -s --max-time 5 http://${IP_INET_GATEWAY%/*}:8080 >/dev/null && \
+ echo -e "${GREEN}✓ PASS${NC}" || echo -e "${RED}✗ FAIL${NC}"
+ kill $pid 2>/dev/null
+ echo ""
+
+ echo -e "${BLUE}Test 3: DNS resolution${NC}"
+ dig @${IP_INET_GATEWAY%/*} google.com +short +time=2 >/dev/null && \
+ echo -e "${GREEN}✓ PASS${NC}" || echo -e "${RED}✗ FAIL${NC}"
+ echo ""
+
+ echo -e "${YELLOW}Note: For full testing, attach your KVMs and test from there${NC}"
+}
+
+# Teardown network
+teardown_network() {
+ echo -e "${GREEN}Tearing down network simulation...${NC}"
+
+ # Kill services
+ [ -f "${STATE_DIR}/dns.pid" ] && kill $(cat "${STATE_DIR}/dns.pid") 2>/dev/null
+ [ -f "${STATE_DIR}/http.pid" ] && kill $(cat "${STATE_DIR}/http.pid") 2>/dev/null
+ [ -f "${STATE_DIR}/icmp.pid" ] && kill $(cat "${STATE_DIR}/icmp.pid") 2>/dev/null
+
+ # Remove traffic control
+ tc qdisc del dev ${VETH_EXIT_HOST} root 2>/dev/null || true
+
+ # Delete bridges
+ ip link set ${BRIDGE_CLIENT} down 2>/dev/null || true
+ ip link set ${BRIDGE_EXIT} down 2>/dev/null || true
+ ip link set ${BRIDGE_WAN} down 2>/dev/null || true
+ ip link del ${BRIDGE_CLIENT} 2>/dev/null || true
+ ip link del ${BRIDGE_EXIT} 2>/dev/null || true
+ ip link del ${BRIDGE_WAN} 2>/dev/null || true
+
+ # Delete namespaces (this removes veth pairs automatically)
+ ip netns del ${NETNS_EXIT} 2>/dev/null || true
+ ip netns del ${NETNS_INTERNET} 2>/dev/null || true
+
+ # Clean iptables
+ iptables -t nat -D POSTROUTING -s 10.10.1.0/24 -o ${BRIDGE_EXIT} -j MASQUERADE 2>/dev/null || true
+
+ # Clean state
+ rm -rf "${STATE_DIR}"
+
+ echo -e "${GREEN}✓ Teardown complete${NC}"
+}
+
+# Main
+check_root
+init_state
+
+case "${1:-}" in
+ setup)
+ setup_network "${2:-100}" "${3:-10}"
+ ;;
+ status)
+ show_status
+ ;;
+ logs)
+ show_logs
+ ;;
+ adjust)
+ adjust_network "$2" "$3"
+ ;;
+ test)
+ run_tests
+ ;;
+ teardown)
+ teardown_network
+ ;;
+ *)
+ usage
+ ;;
+esac
+
+exit 0