1214306Sjulian#!/bin/sh 2214306Sjulian# 3222179Suqs# Copyright (c) 2010, Yavuz Gokirmak 4214306Sjulian# 5214306Sjulian# All rights reserved. 6214306Sjulian# 7214306Sjulian# This source code may be used, modified, copied, distributed, and 8214306Sjulian# sold, in both source and binary form provided that the above 9214306Sjulian# copyright and these terms are retained, verbatim, as the first 10214306Sjulian# lines of this file. Under no circumstances is the author 11214306Sjulian# responsible for the proper functioning of the software nor does 12214306Sjulian# the author assume any responsibility for damages incurred with 13214306Sjulian# its use. 14214306Sjulian# 15214306Sjulian# $FreeBSD$ 16214306Sjulian# 17222179Suqs# This script adds virtual nodes to one of the physical interfaces 18214306Sjulian# visible on your local area network (LAN). Virtual nodes seems real 19222179Suqs# to external observers. 20214306Sjulian# If traceroute is executed to one of virtual nodes, the IP 21222179Suqs# address of the physical interface will not be seen in the output. 22214306Sjulian# Virtual nodes are generated via jails and network connections are 23214306Sjulian# established using ng_bridge(4) and ng_eiface(4) node types. 24214306Sjulian# 25214306Sjulian# To use this script: 26214306Sjulian# 27214306Sjulian# 0. Make your own copy of this example script. 28214306Sjulian# 29214306Sjulian# 1. Edit the definition of ${ETHER_INTF} as described below 30214306Sjulian# to define your real interface connected to the LAN. Virtual nodes 31222179Suqs# will placed on the same physical network as this interface. 32214306Sjulian# 33222179Suqs# 2. Edit the definition of ${TARGET_TOPOLOGY} to define your virtual 34214306Sjulian# nodes. Virtual topology definition includes node names and their 35222179Suqs# IP address. Target top. syntax: ( node1|ip1/24 node2|ip2/24 ... ) 36214306Sjulian# Example 1: ( n1|122.122.122.12/24, n2|122.122.122.13/24 ...) 37214306Sjulian# Example 2: ( n1|2001:b90::14a/125, n1|2001:b90::14b/125 ...) 38214306Sjulian# 39214306Sjulian# 3. Run this script with "start" as the command line argument. 40214306Sjulian# 41214306Sjulian# 4. Stop bridging by running this script with "stop" as the 42214306Sjulian# command line argument. 43222179Suqs# 44222179Suqs# 5. This script uses a template file in order to carry information 45222179Suqs# between start and stop calls. 46214306Sjulian# In the start call, the netgraph interfaces and jails are created. 47214306Sjulian# At the stop phase, all created objects should be removed. 48214306Sjulian# DO NOT delete the temporary file between the start and stop phases. 49214306Sjulian# 50214306Sjulian# To add virtual nodes for multiple independent LANs, create multiple 51214306Sjulian# copies of this script with different variable definitions. 52214306Sjulian# 53214306Sjulian# Target Topology: 54214306Sjulian# 55214306Sjulian# 56214306Sjulian# +---------------+ +---------------+ +---------------+ 57214306Sjulian# | n0 (vimage) | | n1 (vimage) | | nk (vimage) | 58214306Sjulian# | | | | | | 59214306Sjulian# | +-----------+ | | +-----------+ | | +-----------+ | 60214306Sjulian# | | ngeth0 | | | | ngeth1 | | | | ngethk | | 61214306Sjulian# | |(ng_eiface)| | | |(ng_eiface)| | | |(ng_eiface)| | 62214306Sjulian# | +--+-----+--+ | | +--+-----+--+ | | +--+-----+--+ | 63214306Sjulian# | |ether| | | |ether| | | |ether| | 64214306Sjulian# | +--X--+ | | +--X--+ | | +---X-+ | 65214306Sjulian# +-----+ +--------\------+ +--------\------+ +-------/-------+ 66214306Sjulian# |upper|----\ \ip_addr \ip_addr /ip_addr 67214306Sjulian# +-+-----+--+ \ \ \ \ 68214306Sjulian# | em0 | \ +--------+ +-+ \ 69214306Sjulian# |(ng_ether)| +-----------+ \ \ \ 70214306Sjulian# +-+-----+--+ \ \ / \ 71214306Sjulian# |lower| +---------\ \ \ / / 72214306Sjulian# +--X--+ / O--X--O O-X---O O---X-O O--X--O O---X---O 73214306Sjulian# \ | |link0| |link1| |link2| |link3| |linkk+2| 74214306Sjulian# \ / +-O-----O-O-----O-O-----O-O-----O-----O-------O-+ 75214306Sjulian# +---+ | | 76214306Sjulian# | bridge (ng_bridge) | 77214306Sjulian# +-----------------------------------------------+ 78214306Sjulian# 79214306Sjulian# 80214306Sjulian 81214306Sjulian# Give the name of ethernet interface. Virtual nodes will be seen as 82222179Suqs# local neighbours of this interface. 83214306Sjulian 84214306SjulianETHER_INTF="em0" 85214306Sjulian 86222179Suqs# List the names of virtual nodes and their IP addresses. Use ':' 87222179Suqs# character to separate node name from node IP address and netmask. 88214306Sjulian 89214306SjulianTARGET_TOPOLOGY="c1|10.0.2.20/24 c2|10.0.2.21/24 c3|10.0.2.22/24" 90214306Sjulian 91222179Suqs# MAC manufacturer prefix. This can be modified according to needs. 92222179SuqsMAC_PREFIX="00:1d:92" 93214306Sjulian 94222179Suqs# Temporary file is important for proper execution of script. 95214306SjulianTEMP_FILE="/var/tmp/.virtual.lan.tmp" 96214306Sjulian 97214306Sjulian# Set root directory for jails to be created. 98214306SjulianJAIL_PATH="/usr/jails/node" 99214306Sjulian 100214306Sjulian 101214306Sjulian#################################################################### 102214306Sjulian#### Nothing below this point should need to be modified. #### 103214306Sjulian#################################################################### 104214306Sjulian 105214306Sjulian 106214306Sjulian# Start/restart routine. 107214306Sjulianvirtual_lan_start() { 108214306Sjulian 109214306Sjulian # Load netgraph KLD's as necessary. 110222179Suqs 111214306Sjulian for KLD in ng_ether ng_bridge ng_eiface; do 112214306Sjulian if ! kldstat -v | grep -qw ${KLD}; then 113214306Sjulian echo -n "Loading ${KLD}.ko... " 114214306Sjulian kldload ${KLD} || exit 1 115214306Sjulian echo "done" 116214306Sjulian fi 117214306Sjulian done 118214306Sjulian 119214306Sjulian # Reset all interfaces and jails. If temporary file can not be found 120222179Suqs # script assumes that there is no previous configuration. 121222179Suqs 122214306Sjulian if [ ! -e ${TEMP_FILE} ]; then 123214306Sjulian echo "No previous configuration(${TEMP_FILE}) found to clean-up." 124214306Sjulian else 125214306Sjulian echo -n "Cleaning previous configuration..." 126214306Sjulian virtual_lan_stop 127214306Sjulian echo "done" 128222179Suqs fi 129214306Sjulian 130222179Suqs # Create temporary file for usage. This file includes generated 131214306Sjulian # interface names and jail names. All bridges, interfaces and jails 132222179Suqs # are written to file while created. In clean-up process written 133222179Suqs # objects are cleaned (i.e. removed) from system. 134222179Suqs 135214306Sjulian if [ -e ${TEMP_FILE} ]; then 136214306Sjulian touch ${TEMP_FILE} 137214306Sjulian fi 138214306Sjulian 139214306Sjulian echo -n "Verifying ethernet interface existence..." 140214306Sjulian # Verify ethernet interface exist. 141214306Sjulian if ! ngctl info ${ETHER_INTF}: >/dev/null 2>&1; then 142214306Sjulian echo "Error: interface ${ETHER_INTF} does not exist" 143214306Sjulian exit 1 144214306Sjulian fi 145214306Sjulian ifconfig ${ETHER_INTF} up || exit 1 146214306Sjulian echo "done" 147214306Sjulian 148214306Sjulian # Get current number of bridge interfaces in the system. This number 149214306Sjulian # is used to create a name for new bridge. 150214306Sjulian BRIDGE_COUNT=`ngctl l | grep bridge | wc -l | sed -e "s/ //g"` 151214306Sjulian BRIDGE_NAME="bridge${BRIDGE_COUNT}" 152222179Suqs 153214306Sjulian # Create new ng_bridge(4) node and attach it to the ethernet interface. 154214306Sjulian # Connect ng_ether:lower hook to bridge:link0 when creating bridge and 155214306Sjulian # connect ng_ether:upper hook to bridge:link1 after bridge name is set. 156222179Suqs 157214306Sjulian echo "Creating bridge interface: ${BRIDGE_NAME}..." 158214306Sjulian ngctl mkpeer ${ETHER_INTF}: bridge lower link0 || exit 1 159214306Sjulian ngctl name ${ETHER_INTF}:lower ${BRIDGE_NAME} || exit 1 160214306Sjulian ngctl connect ${ETHER_INTF}: ${BRIDGE_NAME}: upper link1 || exit 1 161214306Sjulian echo "Bridge ${BRIDGE_NAME} is created and ${ETHER_INTF} is connected." 162222179Suqs 163214306Sjulian # In the above code block two hooks are connected to bridge interface, 164222179Suqs # therefore LINKNUM is set to 2 indicating total number of connected 165222179Suqs # hooks on the bridge interface. 166214306Sjulian LINKNUM=2 167214306Sjulian 168214306Sjulian # Write name of the bridge to temp file. Clean-up procedure will use 169214306Sjulian # this name to shutdown bridge interface. 170214306Sjulian echo "bridge ${BRIDGE_NAME}" > ${TEMP_FILE} 171214306Sjulian 172214306Sjulian 173214306Sjulian # Attach other interfaces as well. 174214306Sjulian for NODE in ${TARGET_TOPOLOGY}; do 175222179Suqs 176214306Sjulian # Virtual nodes are defined in TARGET_TOPOLOGY variable. They 177214306Sjulian # have the form of 'nodeName|IPaddr'. Below two lines split 178214306Sjulian # node definition to get node name and node IP. 179214306Sjulian 180214306Sjulian NODE_NAME=`echo ${NODE} | awk -F"|" '{print $1}'` 181214306Sjulian NODE_IP=`echo ${NODE} | awk -F"|" '{print $2}'` 182214306Sjulian 183222179Suqs # Create virtual node (jail) with given name and using 184214306Sjulian # JAIL_PATH as root directory for jail. 185214306Sjulian 186222179Suqs echo -n "Creating virtual node (jail) ${NODE_NAME}..." 187214306Sjulian jail -c vnet name=${NODE_NAME} host.hostname=${NODE_NAME} \ 188222179Suqs path=${JAIL_PATH} persist 189214306Sjulian echo "done" 190222179Suqs 191222179Suqs # Write name of the jail to temp file. Clean-up procedure will 192214306Sjulian # use this name to remove jail. 193222179Suqs 194214306Sjulian echo "node ${NODE_NAME}" >> ${TEMP_FILE} 195214306Sjulian 196222179Suqs # Create a ng_eiface object for virtual node. ng_eiface 197214306Sjulian # object has a hook that can be connected to one of bridge 198222179Suqs # links. After creating interface get its automatically 199222179Suqs # generated name for further usage. 200214306Sjulian 201214306Sjulian echo "Creating eiface interface for virtual node ${NODE_NAME}." 202214306Sjulian ngctl mkpeer eiface ether ether 203214306Sjulian EIFACE=`ngctl l | grep ngeth | tail -n 1| awk '{print $2}'` 204222179Suqs echo "Interface ${EIFACE} is created." 205222179Suqs 206214306Sjulian # Write name of the interface to temp file. Clean-up procedure 207214306Sjulian # will use this name to shutdown interface. 208222179Suqs 209214306Sjulian echo "interface ${EIFACE}" >> ${TEMP_FILE} 210222179Suqs 211222179Suqs # Move virtual interface to virtual node. Note that Interface 212214306Sjulian # name will not be changed at the end of this movement. Moved 213214306Sjulian # interface can be seen at the output of ifconfig command in 214214306Sjulian # jail: 'jexec jailname ifconfig' 215214306Sjulian 216222179Suqs echo "Moving ${EIFACE} to ${NODE_NAME}" 217214306Sjulian ifconfig ${EIFACE} vnet ${NODE_NAME} 218222179Suqs 219214306Sjulian # Make lo0 interface localhost. 220214306Sjulian jexec ${NODE_NAME} ifconfig lo0 localhost 221214306Sjulian 222214306Sjulian # Generate a random mac address for virtual interface. First 223214306Sjulian # three octets can be changed by user. Last three octets are 224222179Suqs # generated randomly. 225214306Sjulian M4=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ 226214306Sjulian awk '{ print $1 % 256 }'` 227214306Sjulian M5=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ 228214306Sjulian awk '{ print $1 % 256 }'` 229214306Sjulian M6=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ 230214306Sjulian awk '{ print $1 % 256 }'` 231214306Sjulian 232214306Sjulian MAC=`printf ${MAC_PREFIX}:%02x:%02x:%02x ${M4} ${M5} ${M6}` 233214306Sjulian 234214306Sjulian # Set the link address (mac address) of virtual interface in 235214306Sjulian # virtual node to randomly generated MAC. 236214306Sjulian echo "Setting MAC address of ${EIFACE} to '${MAC}'" 237214306Sjulian jexec ${NODE_NAME} ifconfig ${EIFACE} link $MAC 238214306Sjulian 239222179Suqs # Either IPv4 or IPv6 can be used in this script. Ifconfig 240214306Sjulian # IP setting syntax differs slightly for two IP versions. 241214306Sjulian # For version 4 'inet' keyword is used whereas for version 6 242214306Sjulian # 'inet6' is used. Below line tries to decide which IP version 243222179Suqs # is given and sets IPVER to 'inet' or 'inet6'. 244214306Sjulian 245214306Sjulian IPVER=`echo ${NODE_IP} | awk -F"." '{ split($4,last,"/"); \ 246214306Sjulian if( NF==4 && $1>0 && $1<256 && $2<256 && $3<256 && \ 247214306Sjulian last[1]<256) print "inet"; else print "inet6"}'` 248222179Suqs 249214306Sjulian # Set IP address of virtual interface in virtual node. 250214306Sjulian echo "Setting IP address of ${EIFACE} to '${NODE_IP}'" 251214306Sjulian jexec ${NODE_NAME} ifconfig ${EIFACE} ${IPVER} ${NODE_IP} 252222179Suqs 253214306Sjulian # Connect virtual interface to bridge interface. Syntax is : 254214306Sjulian # ngctl connect INTERFACE: BRIDGE: INTERFACE_HOOK EMPTY_LINK. 255214306Sjulian # Interface has one hook named 'ether' and below line connects 256222179Suqs # ether hook to bridge's first unconnected link. 257222179Suqs 258214306Sjulian echo -n "Connecting ${EIFACE}:ether to ${BRIDGE_NAME}:link${LINKNUM}..." 259214306Sjulian ngctl connect ${EIFACE}: ${BRIDGE_NAME}: ether link${LINKNUM} \ 260214306Sjulian || exit 1 261214306Sjulian echo "done" 262214306Sjulian 263214306Sjulian # Now, bridge has one more connected link thus link count is 264222179Suqs # incremented. 265214306Sjulian LINKNUM=`expr ${LINKNUM} + 1` 266214306Sjulian done 267222179Suqs echo "Virtual LAN established successfully!" 268214306Sjulian 269214306Sjulian} 270214306Sjulian 271214306Sjulian# Stop routine. 272214306Sjulianvirtual_lan_stop() { 273214306Sjulian 274214306Sjulian if [ ! -e ${TEMP_FILE} ]; then 275214306Sjulian echo "Nothing to stop! ${TEMP_FILE}: temp file not found" 276214306Sjulian else 277214306Sjulian 278222179Suqs echo -n "Shutdown bridge interface.." 279214306Sjulian OBJECTS=`cat ${TEMP_FILE} | grep bridge | awk '{print $2}'` 280214306Sjulian for BRIDGE in ${OBJECTS}; do 281214306Sjulian ngctl shutdown ${BRIDGE}: >/dev/null 2>&1 282214306Sjulian done 283214306Sjulian echo "done" 284222179Suqs 285222179Suqs echo -n "Shutdown all eiface interfaces..." 286214306Sjulian OBJECTS=`cat ${TEMP_FILE} | grep interface | awk '{print $2}'` 287214306Sjulian for INTERFACE in ${OBJECTS}; do 288214306Sjulian ngctl shutdown ${INTERFACE}: >/dev/null 2>&1 289214306Sjulian done 290214306Sjulian echo "done" 291222179Suqs 292222179Suqs echo -n "Removing all jails..." 293214306Sjulian OBJECTS=`cat ${TEMP_FILE} | grep node | awk '{print $2}'` 294214306Sjulian for NODE in ${OBJECTS}; do 295214306Sjulian jail -r ${NODE} 296214306Sjulian done 297214306Sjulian echo "done" 298222179Suqs 299222179Suqs echo "Removing tempfile ${TEMP_FILE}" 300214306Sjulian rm ${TEMP_FILE} 301214306Sjulian fi 302222179Suqs echo "Virtual LAN objects removed successfully!" 303214306Sjulian 304214306Sjulian} 305214306Sjulian 306214306Sjulianvirtual_lan_usage() { 307214306Sjulian echo "usage: $0 start [target_topology]" 308214306Sjulian echo " : $0 [ stop | help ]" 309214306Sjulian} 310214306Sjulian 311214306Sjulian 312214306Sjulian# Main entry point. 313214306Sjulian 314214306Sjuliancase $# in 315214306Sjulian 1) 316214306Sjulian case $1 in 317214306Sjulian start) 318214306Sjulian echo -n "Creating default target topology:" 319214306Sjulian echo " ${TARGET_TOPOLOGY}" 320214306Sjulian virtual_lan_start 321214306Sjulian ;; 322214306Sjulian stop) 323214306Sjulian 324214306Sjulian if [ ! -e ${TEMP_FILE} ]; then 325214306Sjulian echo -n "Noting to stop! ${TEMP_FILE}:" 326214306Sjulian echo " temp file not found" 327214306Sjulian else 328214306Sjulian virtual_lan_stop 329222179Suqs fi 330214306Sjulian ;; 331214306Sjulian help) 332214306Sjulian virtual_lan_usage 333214306Sjulian exit 1 334214306Sjulian ;; 335214306Sjulian *) 336214306Sjulian virtual_lan_usage 337214306Sjulian exit 1 338214306Sjulian 339214306Sjulian esac 340214306Sjulian ;; 341214306Sjulian 2) 342214306Sjulian case $1 in 343214306Sjulian start) 344214306Sjulian TARGET_TOPOLOGY=$2 345214306Sjulian echo -n "Creating target topology:" 346214306Sjulian echo "${TARGET_TOPOLOGY}" 347214306Sjulian virtual_lan_start 348214306Sjulian ;; 349214306Sjulian *) 350214306Sjulian virtual_lan_usage 351214306Sjulian exit 1 352214306Sjulian esac 353214306Sjulian ;; 354214306Sjulian 355214306Sjulian *) 356214306Sjulian virtual_lan_usage 357214306Sjulian exit 1 358214306Sjulianesac 359214306Sjulian 360