diff options
Diffstat (limited to 'share/examples/netgraph')
-rw-r--r-- | share/examples/netgraph/ether.bridge | 169 | ||||
-rw-r--r-- | share/examples/netgraph/frame_relay | 45 | ||||
-rw-r--r-- | share/examples/netgraph/ngctl | 172 | ||||
-rw-r--r-- | share/examples/netgraph/raw | 15 | ||||
-rw-r--r-- | share/examples/netgraph/udp.tunnel | 52 | ||||
-rw-r--r-- | share/examples/netgraph/virtual.chain | 369 | ||||
-rw-r--r-- | share/examples/netgraph/virtual.lan | 358 |
7 files changed, 1180 insertions, 0 deletions
diff --git a/share/examples/netgraph/ether.bridge b/share/examples/netgraph/ether.bridge new file mode 100644 index 000000000000..6a9dd5c36c6e --- /dev/null +++ b/share/examples/netgraph/ether.bridge @@ -0,0 +1,169 @@ +#!/bin/sh +# This script sets up an Ethernet bridging network across multiple +# Ethernet interfaces using the ng_bridge(4) and ng_ether(4) netgraph +# node types. +# +# To use this script: +# +# 0. Make your own copy of this example script. +# +# 1. Give your bridging network a name by editing the definition of +# ${BRIDGE_NAME} below. It must be a valid netgraph node name. +# +# 2. Edit the definitions of ${BRIDGE_IFACES} and ${LOCAL_IFACES} +# as described below to define your bridging interfaces. +# +# 3. Run this script with "start" as the command line argument. +# +# 4. Examine bridging statistics by running this script with "stats" +# as the command line argument. +# +# 5. Stop bridging by running this script with "stop" as the +# command line argument. +# +# To run multiple independent bridging networks, create multiple +# copies of this script with different variable definitions. +# +# To make a "brouted" network, with IP being routed and other protocols being +# bridged, add all the interface in the BRIDGE_IFACES to the LOCAL_IFACES. +# If you just want a normal bridge, just one will be enough. +# In some cases you may want some combination. +# + +# Give each bridging network a unique name here. + +BRIDGE_NAME="bnet0" + +# List the names of the interfaces that you want to bridge across +# here in ${BRIDGE_IFACES}. If you want to include the local host +# machine as well then set ${LOCAL_IFACES} as well (they may also be +# listed in ${BRIDGE_IFACES}). Of course, any ${LOCAL_IFACE} must +# be ifconfig(8)ured separately. If you don't want a ${LOCAL_IFACE} +# then assign it the empty string. + +BRIDGE_IFACES="de0 fxp0 fxp1" +LOCAL_IFACES="fxp0 fxp1" + +##################################################################### +#### Everything below this point should not need to be modified. #### +##################################################################### + +# Routine to verify node's existence. +bridge_verify() { + ngctl info ${BRIDGE_NAME}: >/dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "${BRIDGE_NAME}: bridge network not found" + exit 1 + fi +} + +# Routine to get and display link stats. +bridge_linkstats() { + STATS=`ngctl msg ${BRIDGE_NAME}: getstats $1` + if [ $? -ne 0 ]; then + exit 1 + fi + echo "${STATS}" | fmt 2 | awk '/=/ { fl=index($0, "="); \ + printf "%20s = %s\n", substr($0, 0, fl - 1), substr($0, fl + 1); }' +} + +# Start/restart routine. +bridge_start() { + + # Load netgraph KLD's as necessary. + for KLD in ng_ether ng_bridge; do + if ! kldstat -v | grep -qw ${KLD}; then + echo -n "Loading ${KLD}.ko... " + kldload ${KLD} || exit 1 + echo "done" + fi + done + + # Reset all interfaces. + bridge_stop + + # Verify all interfaces exist. + for ETHER in ${BRIDGE_IFACES} ${LOCAL_IFACES}; do + if ! ngctl info ${ETHER}: >/dev/null 2>&1; then + echo "Error: interface ${ETHER} does not exist" + exit 1 + fi + ifconfig ${ETHER} up || exit 1 + done + + # Create new ng_bridge(4) node, attached to the first interface. + FIRSTIF=`echo ${BRIDGE_IFACES} | awk '{ print $1 }'` + ngctl mkpeer ${FIRSTIF}: bridge lower link0 || exit 1 + ngctl name ${FIRSTIF}:lower ${BRIDGE_NAME} || exit 1 + + # Attach other interfaces as well. + LINKNUM=0 + for ETHER in ${BRIDGE_IFACES}; do + if [ ${LINKNUM} != 0 ]; then + ngctl connect ${ETHER}: ${BRIDGE_NAME}: \ + lower link${LINKNUM} || exit 1 + fi + LINKNUM=`expr ${LINKNUM} + 1` + done + + # Hook up local interface, if any. + for LOCAL_IFACE in ${LOCAL_IFACES}; do + ngctl connect ${LOCAL_IFACE}: ${BRIDGE_NAME}: \ + upper link${LINKNUM} || exit 1 + LINKNUM=`expr ${LINKNUM} + 1` + done + + # Set all interfaces in promiscuous mode and don't overwrite src addr. + for ETHER in ${BRIDGE_IFACES}; do + ngctl msg ${ETHER}: setpromisc 1 || exit 1 + ngctl msg ${ETHER}: setautosrc 0 || exit 1 + done +} + +# Stop routine. +bridge_stop() { + ngctl kill ${BRIDGE_NAME}: >/dev/null 2>&1 + for ETHER in ${BRIDGE_IFACES} ${LOCAL_IFACES}; do + ngctl kill ${ETHER}: >/dev/null 2>&1 + done +} + +# Stats routine. +bridge_stats() { + + # Make sure node exists. + bridge_verify + + echo "" + echo "Statistics for bridging network ${BRIDGE_NAME}:" + echo "" + LINKNUM=0 + for ETHER in ${BRIDGE_IFACES}; do + echo "Network interface ${ETHER}:" + bridge_linkstats ${LINKNUM} + LINKNUM=`expr ${LINKNUM} + 1` + done + for LOCAL_IFACE in ${LOCAL_IFACES}; do + echo "Local host interface ${LOCAL_IFACE}:" + bridge_linkstats ${LINKNUM} + LINKNUM=`expr ${LINKNUM} + 1` + done +} + +# Main entry point. +case $1 in + start) + bridge_start + ;; + stats) + bridge_verify + bridge_stats + ;; + stop) + bridge_verify + bridge_stop + ;; + *) + echo "usage: $0 [ start | stop | stats ]" + exit 1 +esac diff --git a/share/examples/netgraph/frame_relay b/share/examples/netgraph/frame_relay new file mode 100644 index 000000000000..0113f76076da --- /dev/null +++ b/share/examples/netgraph/frame_relay @@ -0,0 +1,45 @@ +#!/bin/sh +# script to set up a frame relay link on the sr card. +# The dlci used is selected below. The default is 16 + +CARD=sr0 +DLCI=16 + +# create a frame_relay type node and attach it to the sync port. +ngctl mkpeer ${CARD}: frame_relay rawdata downstream + +# Attach the dlci output of the (de)multiplexor to a new +# Link management protocol node. +ngctl mkpeer ${CARD}:rawdata lmi dlci0 auto0 + +# Also attach dlci 1023, as it needs both to try auto-configuring. +# The Link management protocol is now alive and probing.. +ngctl connect ${CARD}:rawdata ${CARD}:rawdata.dlci0 dlci1023 auto1023 + +# Attach the DLCI(channel) the Telco has assigned you to +# a node to handle whatever protocol encapsulation your peer +# is using. In this case RFC1490 encapsulation. +ngctl mkpeer ${CARD}:rawdata rfc1490 dlci${DLCI} downstream + + +# Attach the ip (inet) protocol output of the protocol mux to the ip (inet) +# input of a netgraph "interface" node (ifconfig should show it as "ng0"). +#if interface ng0 needs to be created use a mkpeer command.. e.g. +ngctl mkpeer ${CARD}:rawdata.dlci${DLCI} iface inet inet + +# if ng0 already exists, use a CONNECT command instead of a mkpeer. e.g. +# ngctl connect ${CARD}:rawdata.dlci${DLCI} ng0: inet inet + +# Then use ifconfig on interface ng0 as usual + +# A variant on this whole set might use the 'name' command to make it more +# readable. But it doesn't work if you have multiple lines or dlcis +# e.g. +# ngctl mkpeer ${CARD}: frame_relay rawdata downstream +# ngctl name ${CARD}:rawdata mux +# ngctl mkpeer mux: lmi dlci0 auto0 +# ngctl name mux:dlci0 lmi +# ngctl connect mux: lmi: dlci1023 auto1023 +# ngctl mkpeer mux: rfc1490 dlci${DLCI} downstream +# ngctl mux:dlci${DLCI} protomux +# ngctl mkpeer protomux: iface inet inet diff --git a/share/examples/netgraph/ngctl b/share/examples/netgraph/ngctl new file mode 100644 index 000000000000..c879cbea7b0f --- /dev/null +++ b/share/examples/netgraph/ngctl @@ -0,0 +1,172 @@ + +# +# This is an example that shows how to send ASCII formatted control +# messages to a node using ngctl(8). +# +# What we will do here create a divert(4) tap. This simply dumps +# out all packets diverted by some ipfw(8) divert rule to the console. +# +# Lines that begin with ``$'' (shell prompt) or ``+'' (ngctl prompt) +# indicate user input +# + +# First, start up ngctl in interactive mode: + + $ ngctl + Available commands: + connect Connects hook <peerhook> of the node at <relpath> to <hook> + debug Get/set debugging verbosity level + help Show command summary or get more help on a specific command + list Show information about all nodes + mkpeer Create and connect a new node to the node at "path" + msg Send a netgraph control message to the node at "path" + name Assign name <name> to the node at <path> + read Read and execute commands from a file + rmhook Disconnect hook "hook" of the node at "path" + show Show information about the node at <path> + shutdown Shutdown the node at <path> + status Get human readable status information from the node at <path> + types Show information about all installed node types + quit Exit program + + + +# Now let's create a ng_ksocket(4) node, in the family PF_DIVERT, +# of type SOCK_RAW: + + + mkpeer ksocket foo divert/raw/0 + +# Note that ``foo'' is the hook name on the socket node, which can be +# anything. The ``inet/raw/divert'' is the hook name on the ksocket +# node, which tells it what kind of socket to create. + +# Lets give our ksocket node a global name. How about ``fred'': + + + name foo fred + +# Note that we used ngctl's ``name'' command to do this. However, +# the following manually constructed netgraph message would have +# accomplished the exact same thing: + + + msg foo name { name="fred" } + +# Here we are using the ASCII <-> binary control message conversion +# routines. ngctl does this for us automatically when we use the +# ``msg'' command. + +# Now lets bind the socket associated with the ksocket node to a port +# supplied by the system. We do this by sending the ksocket node a +# ``bind'' control message. Again, ngctl does the conversion of the +# control message from ASCII to binary behind the scenes. + + + msg fred: bind inet/192.168.1.1 + +# The ksocket accepts arbitrary sockaddr structures, but also has +# special support for the PF_LOCAL and PF_INET protocol families. +# That is why we can specify the struct sockaddr argument to the +# ``bind'' command as ``inet/192.168.1.1'' (since we didn't specify +# a port number, it's assumed to be zero). We could have also +# relied on the generic sockaddr syntax and instead said this: + + + msg fred: bind { family=2 len=16 data=[ 2=192 168 1 1 ] } + +# This is what you would have to do for protocol families other +# that PF_INET and PF_LOCAL, at least until special handling for +# new ones is added. + +# The reason for the ``2=192'' is to skip the two byte IP port number, +# which causes it to be set to zero, the default value for integral +# types when parsing. Now since we didn't ask for a specific port +# number, we need to do a ``getname'' to see what port number we got: + + + msg fred: getname + Rec'd response "getname" (5) from "fred:": + Args: inet/192.168.1.1:1029 + +# As soon as we sent the message, we got back a response. Here +# ngctl is telling us that it received a control message with the +# NGF_RESP (response) flag set, the response was to a prior ``getname'' +# control message, that the originator was the node addressable +# as ``fred:''. The message arguments field is then displayed to +# us in its ASCII form. In this case, what we get back is a struct +# sockaddr, and there we see that our port number is 1029. + +# So now let's add the ipfw divert rule for whatever packets we +# want to see. How about anything from 192.168.1.129. + + + ^Z + Suspended + $ ipfw add 100 divert 1029 ip from 192.168.1.129 to any + 00100 divert 1029 ip from 192.168.1.129 to any + $ fg + +# Now watch what happens when we try to ping from that machine: + + + + Rec'd data packet on hook "foo": + 0000: 45 00 00 3c 57 00 00 00 20 01 bf ee c0 a8 01 81 E..<W... ....... + 0010: c0 a8 01 01 08 00 49 5c 03 00 01 00 61 62 63 64 ......I\....abcd + 0020: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 efghijklmnopqrst + 0030: 75 76 77 61 62 63 64 65 66 67 68 69 uvwabcdefghi + + + Rec'd data packet on hook "foo": + 0000: 45 00 00 3c 58 00 00 00 20 01 be ee c0 a8 01 81 E..<X... ....... + 0010: c0 a8 01 01 08 00 48 5c 03 00 02 00 61 62 63 64 ......H\....abcd + 0020: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 efghijklmnopqrst + 0030: 75 76 77 61 62 63 64 65 66 67 68 69 uvwabcdefghi + + + Rec'd data packet on hook "foo": + 0000: 45 00 00 3c 59 00 00 00 20 01 bd ee c0 a8 01 81 E..<Y... ....... + 0010: c0 a8 01 01 08 00 47 5c 03 00 03 00 61 62 63 64 ......G\....abcd + 0020: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 efghijklmnopqrst + 0030: 75 76 77 61 62 63 64 65 66 67 68 69 uvwabcdefghi + + + +# So we're seeing the output from the ksocket socket appear on the ``foo'' +# hook of ngctl's socket node. Since the packets are getting diverted, +# the 192.168.1.129 machine doesn't see any response from us. + +# Of course, any type of socket can be used, even TCP: + + + mkpeer ksocket bar inet/stream/tcp + + msg bar connect inet/192.168.1.33:13 + ngctl: send msg: Operation now in progress + + + Rec'd data packet on hook "foo": + 0000: 4d 6f 6e 20 4e 6f 76 20 32 39 20 31 37 3a 34 38 Mon Nov 29 17:48 + 0010: 3a 33 37 20 31 39 39 39 0d 0a :37 1999.. + + + +# Or, UNIX domain: + + + mkpeer ksocket bar local/stream/0 + + msg bar bind local/"/tmp/bar.socket" + + + +# Here's an example of a more complicated ASCII control message argument. +# If you look in /sys/netgraph/ng_message.h, you will see that a node +# responds to a NGM_LISTHOOKS with a struct hooklist, which contains +# an array of struct linkinfo: +# +# /* Structure used for NGM_LISTHOOKS */ +# struct linkinfo { +# char ourhook[NG_HOOKSIZ]; /* hook name */ +# char peerhook[NG_HOOKSIZ]; /* peer hook */ +# struct nodeinfo nodeinfo; +# }; +# +# struct hooklist { +# struct nodeinfo nodeinfo; /* node information */ +# struct linkinfo link[0]; /* info about each hook */ +# }; +# +# By sending a node the ``listhooks'' command using ngctl, we can see +# this structure in ASCII form (lines wrapped for readability): + + + msg bar bind local/"/tmp/bar.socket" + + msg bar listhooks + Rec'd response "listhooks" (7) from "bar": + Args: { nodeinfo={ type="ksocket" id=9 hooks=1 } + linkinfo=[ { ourhook="local/stream/0" peerhook="bar" + nodeinfo={ name="ngctl1327" type="socket" id=8 hooks=1 } } ] } + + diff --git a/share/examples/netgraph/raw b/share/examples/netgraph/raw new file mode 100644 index 000000000000..44196780fd0c --- /dev/null +++ b/share/examples/netgraph/raw @@ -0,0 +1,15 @@ +#!/bin/sh +# script to connect a raw synchronous card to a system interface. +# Assumes the file if_sr was compiled with options NETGRAPH. + +CARD=sr0 + +# create an interface "ng0" and attach it to the sync port. +# The packets had jolly well better be IP because we are not discriminating. +ngctl mkpeer ${CARD}: iface rawdata inet + +# if ng0 already exists, use a CONNECT command instead of a mkpeer. e.g. +# ngctl connect ${CARD}: ng0: rawdata inet + +# Then use ifconfig on interface ng0 as usual + diff --git a/share/examples/netgraph/udp.tunnel b/share/examples/netgraph/udp.tunnel new file mode 100644 index 000000000000..fb589ed7e15f --- /dev/null +++ b/share/examples/netgraph/udp.tunnel @@ -0,0 +1,52 @@ +#!/bin/sh + +# This script sets up a virtual point-to-point WAN link between +# two subnets, using UDP packets as the ``WAN connection.'' +# The two subnets might be non-routable addresses behind a +# firewall. +# + +# Here define the local and remote inside networks as well +# as the local and remote outside IP addresses and UDP port +# number that will be used for the tunnel. +# +LOC_INTERIOR_IP=192.168.1.1 +LOC_EXTERIOR_IP=1.1.1.1 +REM_INTERIOR_IP=192.168.2.1 +REM_EXTERIOR_IP=2.2.2.2 +REM_INSIDE_NET=192.168.2.0 +UDP_TUNNEL_PORT=4028 + +# Create the interface node ``ng0'' if it doesn't exist already, +# otherwise just make sure it's not connected to anything. +# In FreeBSD, interfaces cannot be removed so it might already +# be there from before. +# +if ifconfig ng0 >/dev/null 2>&1; then + ifconfig ng0 inet down delete >/dev/null 2>&1 + ngctl shutdown ng0: +else + ngctl mkpeer iface dummy inet +fi + +# Attach a UDP socket to the ``inet'' hook of the interface node +# using the ng_ksocket(4) node type. +# +ngctl mkpeer ng0: ksocket inet inet/dgram/udp + +# Bind the UDP socket to the local external IP address and port +# +ngctl msg ng0:inet bind inet/${LOC_EXTERIOR_IP}:${UDP_TUNNEL_PORT} + +# Connect the UDP socket to the peer's external IP address and port +# +ngctl msg ng0:inet connect inet/${REM_EXTERIOR_IP}:${UDP_TUNNEL_PORT} + +# Configure the point-to-point interface +# +ifconfig ng0 ${LOC_INTERIOR_IP} ${REM_INTERIOR_IP} + +# Add a route to the peer's interior network via the tunnel +# +route add ${REM_INSIDE_NET} ${REM_INTERIOR_IP} + diff --git a/share/examples/netgraph/virtual.chain b/share/examples/netgraph/virtual.chain new file mode 100644 index 000000000000..615f7da20a52 --- /dev/null +++ b/share/examples/netgraph/virtual.chain @@ -0,0 +1,369 @@ +#!/bin/sh +# +# Copyright (c) 2010, Yavuz Gokirmak +# +# All rights reserved. +# +# This source code may be used, modified, copied, distributed, and +# sold, in both source and binary form provided that the above +# copyright and these terms are retained, verbatim, as the first +# lines of this file. Under no circumstances is the author +# responsible for the proper functioning of the software nor does +# the author assume any responsibility for damages incurred with +# its use. +# +# +# This script creates and connects n router like nodes. Complex wide +# area topologies can be created with the help of script. +# +# Virtual nodes are generated via jails and network connections are +# established using ng_eiface(4) node types. +# +# To use this script: +# +# 0. Make your own copy of this example script. +# +# 1. Edit the definition of ${TARGET_TOPOLOGY} to define your virtual +# nodes. Virtual topology definition includes node names and their +# IP address. Target top. syntax: ( name|ip<->name|ip ... ) +# Example 1: ( n1|10.0.2.1/30<->n2|10.0.2.2/30 ...) +# Example 2: ( n1|2001:b90::14a/125<->n1|2001:b90::14b/125 ...) +# +# 2. Run this script with "start" as the command line argument. +# +# 3. Add necessary static route commands for each virtual node. For +# example assume you have three virtual nodes connected each other +# like a chain (n1 is connected to n2, n2 is connected to n3). +# In order to establish connectivity among these virtual nodes, +# you have to add default routes to node n1 and node n3. Example +# static route command is: +# STATIC_ROUTE0="jexec n1 route add -inet default 10.0.2.2" +# STATIC_ROUTE1="jexec n3 route add -inet default 10.0.2.5" +# After defining default routes with above format you have to set +# the total number of static route commands as: +# STATIC_ROUTE_CNT=2 +# +# 4. Stop bridging by running this script with "stop" as the +# command line argument. +# +# 5. This script uses a template file in order to carry information +# between start and stop calls. +# In the start call, the netgraph interfaces and jails are created. +# At the stop phase, all created objects should be removed. +# DO NOT delete the temporary file between the start and stop phases. +# +# Target Topology: +# +# +---------------+ +---------------------------------------------+ +# | n1 (vimage) | | n2 (vimage) | +# | | | | +# | +-----------+ | | +-----------+ +-----------+ +-----------+ | +# | | ngeth0 | | | | ngeth1 | | ngeth2 | | ngeth4 | | +# | |(ng_eiface)| | | |(ng_eiface)| |(ng_eiface)| |(ng_eiface)| | +# | +--+-----+--+ | | +--+-----+--+ +--+-----+--+ +--+-----+--+ | +# | |ether| | | |ether| |ether| |ether| | +# | +-X---+ | | +--X--+ +--X--+ +--X--+ | +# +-------X-------+ +------X--------------X---------------X-------+ +# X X X X +# X X X X +# XXXXXXXXXXXXXXX X X +# X X +# +--------X------+ +--------X------+ +# | -+--X--+- | | -+--X--+- | +# | |ether| | | |ether| | +# | +--+-----+--+ | | +--+-----+--+ | +# | | ngeth3 | | | | ngeth5 | | +# | |(ng_eiface)| | | |(ng_eiface)| | +# | +-----------+ | | +-----------+ | +# | | | | +# | n3 (vimage) | | n4 (vimage) | +# +---------------+ +---------------+ +# +# +# + +# List the names of virtual nodes and their IP addresses. Use ':' +# character to separate node name from node IP address and netmask. + +TARGET_TOPOLOGY="n1|10.0.2.1/30<->n2|10.0.2.2/30 n2|10.0.2.5/30<->n3|10.0.2.6/30 n2|10.0.2.9/30<->n4|10.0.2.10/30" +STATIC_ROUTE0="jexec n1 route add -inet default 10.0.2.2" +STATIC_ROUTE1="jexec n3 route add -inet default 10.0.2.5" +STATIC_ROUTE2="jexec n4 route add -inet default 10.0.2.9" +STATIC_ROUTE_CNT=3 + +# MAC manufacturer prefix. This can be modified according to needs. +MAC_PREFIX="00:1d:92" + +# Temporary file is important for proper execution of script. +TEMP_FILE="/var/tmp/.virtual.chain.tmp" + +# Set root directory for jails to be created. +JAIL_PATH="/usr/jails/router" + + +#################################################################### +#### Nothing below this point should need to be modified. #### +#################################################################### + + +# Start/restart routine. +virtual_chain_start() { + + # Load netgraph KLD's as necessary. + + for KLD in ng_ether ng_bridge ng_eiface; do + if ! kldstat -v | grep -qw ${KLD}; then + echo -n "Loading ${KLD}.ko... " + kldload ${KLD} || exit 1 + echo "done" + fi + done + + # Reset all interfaces and jails. If temporary file can not be found + # script assumes that there is no previous configuration. + + if [ ! -e ${TEMP_FILE} ]; then + echo "No previous configuration(${TEMP_FILE}) found to clean-up." + else + echo -n "Cleaning previous configuration..." + virtual_chain_stop + echo "done" + fi + + # Create temporary file for usage. This file includes generated + # interface names and jail names. All bridges, interfaces and jails + # are written to file while created. In clean-up process written + # objects are cleaned (i.e. removed) from system. + + if [ -e ${TEMP_FILE} ]; then + touch ${TEMP_FILE} + fi + + + # Attach other interfaces as well. + for CONNECTION in ${TARGET_TOPOLOGY}; do + + # Virtual connections are defined in TARGET_TOPOLOGY variable. + # They have the form of 'nodeName|IPaddr'. Below two lines split + + PEER1=`echo ${CONNECTION} | awk -F"<->" '{print $1}'` + PEER1_NAME=`echo ${PEER1} | awk -F"|" '{print $1}'` + PEER1_IP=`echo ${PEER1} | awk -F"|" '{print $2}'` + + PEER2=`echo ${CONNECTION} | awk -F"<->" '{print $2}'` + PEER2_NAME=`echo ${PEER2} | awk -F"|" '{print $1}'` + PEER2_IP=`echo ${PEER2} | awk -F"|" '{print $2}'` + + # !!! if not created already.. + # Create virtual node (jail) with given name and using + # JAIL_PATH as root directory for jail. + + virtual_chain_create_peer_if_necessary ${PEER1_NAME} + virtual_chain_create_peer_if_necessary ${PEER2_NAME} + + # create an interface for peer with the given peer IP. Get interface + # for future use; you will connect this interface to the other + # peers' (PEER2) interface. + virtual_chain_create_interface_with_ip ${PEER1_NAME} ${PEER1_IP} + PEER1_INTERFACE=${RET_INTERFACE} + + # create an interface for peer with the given peer IP. Get interface + # for future use; you will connect this interface to the other + # peers' (PEER2) interface. + virtual_chain_create_interface_with_ip ${PEER2_NAME} ${PEER2_IP} + PEER2_INTERFACE=${RET_INTERFACE} + + # Connect virtual interface to other interface. Syntax is : + # ngctl connect INTERFACE1: INTERFACE2: ether ether. + + echo -n "Connecting ${PEER1_INTERFACE}:ether to ${PEER2_INTERFACE}:ether..." + ngctl connect ${PEER1_INTERFACE}: ${PEER2_INTERFACE}: ether ether \ + || exit 1 + echo "done" + + done + + # Executes static route add commands. + i=0 + while [ $i != $STATIC_ROUTE_CNT ]; do + eval ROUTE=\${STATIC_ROUTE${i}} + ret=`${ROUTE}` + i=`expr $i + 1` + done + + echo "Virtual WAN established successfully!" +} + +virtual_chain_create_interface_with_ip() { + + NODE_NAME=$1 + NODE_IP=$2 + + # Create a ng_eiface object for virtual node. ng_eiface + # object has a hook that can be connected to one of bridge + # links. After creating interface get its automatically + # generated name for further usage. + + echo "Creating eiface interface for virtual node ${NODE_NAME}." + ngctl mkpeer eiface ether ether + EIFACE=`ngctl l | grep ngeth | tail -n 1| awk '{print $2}'` + echo "Interface ${EIFACE} is created." + + # Write name of the interface to temp file. Clean-up procedure + # will use this name to shutdown interface. + + echo "interface ${EIFACE}" >> ${TEMP_FILE} + + # Move virtual interface to virtual node. Note that Interface + # name will not be changed at the end of this movement. Moved + # interface can be seen at the output of ifconfig command in + # jail: 'jexec jailname ifconfig' + + echo "Moving ${EIFACE} to ${NODE_NAME}" + ifconfig ${EIFACE} vnet ${NODE_NAME} + + # Make lo0 interface localhost. + jexec ${NODE_NAME} ifconfig lo0 localhost + + # Generate a random mac address for virtual interface. First + # three octets can be changed by user. Last three octets are + # generated randomly. + M4=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ + awk '{ print $1 % 256 }'` + M5=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ + awk '{ print $1 % 256 }'` + M6=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ + awk '{ print $1 % 256 }'` + + MAC=`printf ${MAC_PREFIX}:%02x:%02x:%02x ${M4} ${M5} ${M6}` + + # Set the link address (mac address) of virtual interface in + # virtual node to randomly generated MAC. + echo "Setting MAC address of ${EIFACE} to '${MAC}'" + jexec ${NODE_NAME} ifconfig ${EIFACE} link $MAC + + # Either IPv4 or IPv6 can be used in this script. Ifconfig + # IP setting syntax differs slightly for two IP versions. + # For version 4 'inet' keyword is used whereas for version 6 + # 'inet6' is used. Below line tries to decide which IP version + # is given and sets IPVER to 'inet' or 'inet6'. + + IPVER=`echo ${NODE_IP} | awk -F"." '{ split($4,last,"/"); \ + if( NF==4 && $1>0 && $1<256 && $2<256 && $3<256 && \ + last[1]<256) print "inet"; else print "inet6"}'` + + # Set IP address of virtual interface in virtual node. + echo "Setting IP address of ${EIFACE} to '${NODE_IP}'" + jexec ${NODE_NAME} ifconfig ${EIFACE} ${IPVER} ${NODE_IP} + + RET_INTERFACE=${EIFACE} +} + +virtual_chain_create_peer_if_necessary() { + + if ! grep -q $1 ${TEMP_FILE} ; then + + echo -n "Creating virtual node (jail) ${1}..." + jail -c vnet name=${1} host.hostname=${1} \ + path=${JAIL_PATH} persist + jexec ${1} sysctl -w net.inet.ip.forwarding=1 + jexec ${1} sysctl -w net.inet6.ip6.forwarding=1 + echo "done" + + # Write name of the jail to temp file. Clean-up + # procedure will use this name to remove jail. + + echo "node ${1}" >> ${TEMP_FILE} + fi + +} + +# Stop routine. +virtual_chain_stop() { + + if [ ! -e ${TEMP_FILE} ]; then + echo "Nothing to stop! ${TEMP_FILE}: temp file not found" + else + + echo -n "Shutdown bridge interface.." + OBJECTS=`cat ${TEMP_FILE} | grep bridge | awk '{print $2}'` + for BRIDGE in ${OBJECTS}; do + ngctl shutdown ${BRIDGE}: >/dev/null 2>&1 + done + echo "done" + + echo -n "Shutdown all eiface interfaces..." + OBJECTS=`cat ${TEMP_FILE} | grep interface | awk '{print $2}'` + for INTERFACE in ${OBJECTS}; do + ngctl shutdown ${INTERFACE}: >/dev/null 2>&1 + done + echo "done" + + echo -n "Removing all jails..." + OBJECTS=`cat ${TEMP_FILE} | grep node | awk '{print $2}'` + for NODE in ${OBJECTS}; do + jail -r ${NODE} + done + echo "done" + + echo "Removing tempfile ${TEMP_FILE}" + rm ${TEMP_FILE} + fi + echo "Virtual LAN objects removed successfully!" + +} + +virtual_chain_usage() { + echo "usage: $0 start [target_topology]" + echo " : $0 [ stop | help ]" +} + + +# Main entry point. + +case $# in + 1) + case $1 in + start) + echo -n "Creating default target topology:" + echo " ${TARGET_TOPOLOGY}" + virtual_chain_start + ;; + stop) + + if [ ! -e ${TEMP_FILE} ]; then + echo -n "Noting to stop! ${TEMP_FILE}:" + echo " temp file not found" + else + virtual_chain_stop + fi + ;; + help) + virtual_chain_usage + exit 1 + ;; + *) + virtual_chain_usage + exit 1 + + esac + ;; + 2) + case $1 in + start) + TARGET_TOPOLOGY=$2 + echo -n "Creating target topology:" + echo "${TARGET_TOPOLOGY}" + virtual_chain_start + ;; + *) + virtual_chain_usage + exit 1 + esac + ;; + + *) + virtual_chain_usage + exit 1 +esac + diff --git a/share/examples/netgraph/virtual.lan b/share/examples/netgraph/virtual.lan new file mode 100644 index 000000000000..2ec47aa08b51 --- /dev/null +++ b/share/examples/netgraph/virtual.lan @@ -0,0 +1,358 @@ +#!/bin/sh +# +# Copyright (c) 2010, Yavuz Gokirmak +# +# All rights reserved. +# +# This source code may be used, modified, copied, distributed, and +# sold, in both source and binary form provided that the above +# copyright and these terms are retained, verbatim, as the first +# lines of this file. Under no circumstances is the author +# responsible for the proper functioning of the software nor does +# the author assume any responsibility for damages incurred with +# its use. +# +# +# This script adds virtual nodes to one of the physical interfaces +# visible on your local area network (LAN). Virtual nodes seems real +# to external observers. +# If traceroute is executed to one of virtual nodes, the IP +# address of the physical interface will not be seen in the output. +# Virtual nodes are generated via jails and network connections are +# established using ng_bridge(4) and ng_eiface(4) node types. +# +# To use this script: +# +# 0. Make your own copy of this example script. +# +# 1. Edit the definition of ${ETHER_INTF} as described below +# to define your real interface connected to the LAN. Virtual nodes +# will placed on the same physical network as this interface. +# +# 2. Edit the definition of ${TARGET_TOPOLOGY} to define your virtual +# nodes. Virtual topology definition includes node names and their +# IP address. Target top. syntax: ( node1|ip1/24 node2|ip2/24 ... ) +# Example 1: ( n1|122.122.122.12/24, n2|122.122.122.13/24 ...) +# Example 2: ( n1|2001:b90::14a/125, n1|2001:b90::14b/125 ...) +# +# 3. Run this script with "start" as the command line argument. +# +# 4. Stop bridging by running this script with "stop" as the +# command line argument. +# +# 5. This script uses a template file in order to carry information +# between start and stop calls. +# In the start call, the netgraph interfaces and jails are created. +# At the stop phase, all created objects should be removed. +# DO NOT delete the temporary file between the start and stop phases. +# +# To add virtual nodes for multiple independent LANs, create multiple +# copies of this script with different variable definitions. +# +# Target Topology: +# +# +# +---------------+ +---------------+ +---------------+ +# | n0 (vimage) | | n1 (vimage) | | nk (vimage) | +# | | | | | | +# | +-----------+ | | +-----------+ | | +-----------+ | +# | | ngeth0 | | | | ngeth1 | | | | ngethk | | +# | |(ng_eiface)| | | |(ng_eiface)| | | |(ng_eiface)| | +# | +--+-----+--+ | | +--+-----+--+ | | +--+-----+--+ | +# | |ether| | | |ether| | | |ether| | +# | +--X--+ | | +--X--+ | | +---X-+ | +# +-----+ +--------\------+ +--------\------+ +-------/-------+ +# |upper|----\ \ip_addr \ip_addr /ip_addr +# +-+-----+--+ \ \ \ \ +# | em0 | \ +--------+ +-+ \ +# |(ng_ether)| +-----------+ \ \ \ +# +-+-----+--+ \ \ / \ +# |lower| +---------\ \ \ / / +# +--X--+ / O--X--O O-X---O O---X-O O--X--O O---X---O +# \ | |link0| |link1| |link2| |link3| |linkk+2| +# \ / +-O-----O-O-----O-O-----O-O-----O-----O-------O-+ +# +---+ | | +# | bridge (ng_bridge) | +# +-----------------------------------------------+ +# +# + +# Give the name of ethernet interface. Virtual nodes will be seen as +# local neighbours of this interface. + +ETHER_INTF="em0" + +# List the names of virtual nodes and their IP addresses. Use ':' +# character to separate node name from node IP address and netmask. + +TARGET_TOPOLOGY="c1|10.0.2.20/24 c2|10.0.2.21/24 c3|10.0.2.22/24" + +# MAC manufacturer prefix. This can be modified according to needs. +MAC_PREFIX="00:1d:92" + +# Temporary file is important for proper execution of script. +TEMP_FILE="/var/tmp/.virtual.lan.tmp" + +# Set root directory for jails to be created. +JAIL_PATH="/usr/jails/node" + + +#################################################################### +#### Nothing below this point should need to be modified. #### +#################################################################### + + +# Start/restart routine. +virtual_lan_start() { + + # Load netgraph KLD's as necessary. + + for KLD in ng_ether ng_bridge ng_eiface; do + if ! kldstat -v | grep -qw ${KLD}; then + echo -n "Loading ${KLD}.ko... " + kldload ${KLD} || exit 1 + echo "done" + fi + done + + # Reset all interfaces and jails. If temporary file can not be found + # script assumes that there is no previous configuration. + + if [ ! -e ${TEMP_FILE} ]; then + echo "No previous configuration(${TEMP_FILE}) found to clean-up." + else + echo -n "Cleaning previous configuration..." + virtual_lan_stop + echo "done" + fi + + # Create temporary file for usage. This file includes generated + # interface names and jail names. All bridges, interfaces and jails + # are written to file while created. In clean-up process written + # objects are cleaned (i.e. removed) from system. + + if [ -e ${TEMP_FILE} ]; then + touch ${TEMP_FILE} + fi + + echo -n "Verifying ethernet interface existence..." + # Verify ethernet interface exist. + if ! ngctl info ${ETHER_INTF}: >/dev/null 2>&1; then + echo "Error: interface ${ETHER_INTF} does not exist" + exit 1 + fi + ifconfig ${ETHER_INTF} up || exit 1 + echo "done" + + # Get current number of bridge interfaces in the system. This number + # is used to create a name for new bridge. + BRIDGE_COUNT=`ngctl l | grep bridge | wc -l | sed -e "s/ //g"` + BRIDGE_NAME="bridge${BRIDGE_COUNT}" + + # Create new ng_bridge(4) node and attach it to the ethernet interface. + # Connect ng_ether:lower hook to bridge:link0 when creating bridge and + # connect ng_ether:upper hook to bridge:link1 after bridge name is set. + + echo "Creating bridge interface: ${BRIDGE_NAME}..." + ngctl mkpeer ${ETHER_INTF}: bridge lower link0 || exit 1 + ngctl name ${ETHER_INTF}:lower ${BRIDGE_NAME} || exit 1 + ngctl connect ${ETHER_INTF}: ${BRIDGE_NAME}: upper link1 || exit 1 + echo "Bridge ${BRIDGE_NAME} is created and ${ETHER_INTF} is connected." + + # In the above code block two hooks are connected to bridge interface, + # therefore LINKNUM is set to 2 indicating total number of connected + # hooks on the bridge interface. + LINKNUM=2 + + # Write name of the bridge to temp file. Clean-up procedure will use + # this name to shutdown bridge interface. + echo "bridge ${BRIDGE_NAME}" > ${TEMP_FILE} + + + # Attach other interfaces as well. + for NODE in ${TARGET_TOPOLOGY}; do + + # Virtual nodes are defined in TARGET_TOPOLOGY variable. They + # have the form of 'nodeName|IPaddr'. Below two lines split + # node definition to get node name and node IP. + + NODE_NAME=`echo ${NODE} | awk -F"|" '{print $1}'` + NODE_IP=`echo ${NODE} | awk -F"|" '{print $2}'` + + # Create virtual node (jail) with given name and using + # JAIL_PATH as root directory for jail. + + echo -n "Creating virtual node (jail) ${NODE_NAME}..." + jail -c vnet name=${NODE_NAME} host.hostname=${NODE_NAME} \ + path=${JAIL_PATH} persist + echo "done" + + # Write name of the jail to temp file. Clean-up procedure will + # use this name to remove jail. + + echo "node ${NODE_NAME}" >> ${TEMP_FILE} + + # Create a ng_eiface object for virtual node. ng_eiface + # object has a hook that can be connected to one of bridge + # links. After creating interface get its automatically + # generated name for further usage. + + echo "Creating eiface interface for virtual node ${NODE_NAME}." + ngctl mkpeer eiface ether ether + EIFACE=`ngctl l | grep ngeth | tail -n 1| awk '{print $2}'` + echo "Interface ${EIFACE} is created." + + # Write name of the interface to temp file. Clean-up procedure + # will use this name to shutdown interface. + + echo "interface ${EIFACE}" >> ${TEMP_FILE} + + # Move virtual interface to virtual node. Note that Interface + # name will not be changed at the end of this movement. Moved + # interface can be seen at the output of ifconfig command in + # jail: 'jexec jailname ifconfig' + + echo "Moving ${EIFACE} to ${NODE_NAME}" + ifconfig ${EIFACE} vnet ${NODE_NAME} + + # Make lo0 interface localhost. + jexec ${NODE_NAME} ifconfig lo0 localhost + + # Generate a random mac address for virtual interface. First + # three octets can be changed by user. Last three octets are + # generated randomly. + M4=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ + awk '{ print $1 % 256 }'` + M5=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ + awk '{ print $1 % 256 }'` + M6=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ + awk '{ print $1 % 256 }'` + + MAC=`printf ${MAC_PREFIX}:%02x:%02x:%02x ${M4} ${M5} ${M6}` + + # Set the link address (mac address) of virtual interface in + # virtual node to randomly generated MAC. + echo "Setting MAC address of ${EIFACE} to '${MAC}'" + jexec ${NODE_NAME} ifconfig ${EIFACE} link $MAC + + # Either IPv4 or IPv6 can be used in this script. Ifconfig + # IP setting syntax differs slightly for two IP versions. + # For version 4 'inet' keyword is used whereas for version 6 + # 'inet6' is used. Below line tries to decide which IP version + # is given and sets IPVER to 'inet' or 'inet6'. + + IPVER=`echo ${NODE_IP} | awk -F"." '{ split($4,last,"/"); \ + if( NF==4 && $1>0 && $1<256 && $2<256 && $3<256 && \ + last[1]<256) print "inet"; else print "inet6"}'` + + # Set IP address of virtual interface in virtual node. + echo "Setting IP address of ${EIFACE} to '${NODE_IP}'" + jexec ${NODE_NAME} ifconfig ${EIFACE} ${IPVER} ${NODE_IP} + + # Connect virtual interface to bridge interface. Syntax is : + # ngctl connect INTERFACE: BRIDGE: INTERFACE_HOOK EMPTY_LINK. + # Interface has one hook named 'ether' and below line connects + # ether hook to bridge's first unconnected link. + + echo -n "Connecting ${EIFACE}:ether to ${BRIDGE_NAME}:link${LINKNUM}..." + ngctl connect ${EIFACE}: ${BRIDGE_NAME}: ether link${LINKNUM} \ + || exit 1 + echo "done" + + # Now, bridge has one more connected link thus link count is + # incremented. + LINKNUM=`expr ${LINKNUM} + 1` + done + echo "Virtual LAN established successfully!" + +} + +# Stop routine. +virtual_lan_stop() { + + if [ ! -e ${TEMP_FILE} ]; then + echo "Nothing to stop! ${TEMP_FILE}: temp file not found" + else + + echo -n "Shutdown bridge interface.." + OBJECTS=`cat ${TEMP_FILE} | grep bridge | awk '{print $2}'` + for BRIDGE in ${OBJECTS}; do + ngctl shutdown ${BRIDGE}: >/dev/null 2>&1 + done + echo "done" + + echo -n "Shutdown all eiface interfaces..." + OBJECTS=`cat ${TEMP_FILE} | grep interface | awk '{print $2}'` + for INTERFACE in ${OBJECTS}; do + ngctl shutdown ${INTERFACE}: >/dev/null 2>&1 + done + echo "done" + + echo -n "Removing all jails..." + OBJECTS=`cat ${TEMP_FILE} | grep node | awk '{print $2}'` + for NODE in ${OBJECTS}; do + jail -r ${NODE} + done + echo "done" + + echo "Removing tempfile ${TEMP_FILE}" + rm ${TEMP_FILE} + fi + echo "Virtual LAN objects removed successfully!" + +} + +virtual_lan_usage() { + echo "usage: $0 start [target_topology]" + echo " : $0 [ stop | help ]" +} + + +# Main entry point. + +case $# in + 1) + case $1 in + start) + echo -n "Creating default target topology:" + echo " ${TARGET_TOPOLOGY}" + virtual_lan_start + ;; + stop) + + if [ ! -e ${TEMP_FILE} ]; then + echo -n "Noting to stop! ${TEMP_FILE}:" + echo " temp file not found" + else + virtual_lan_stop + fi + ;; + help) + virtual_lan_usage + exit 1 + ;; + *) + virtual_lan_usage + exit 1 + + esac + ;; + 2) + case $1 in + start) + TARGET_TOPOLOGY=$2 + echo -n "Creating target topology:" + echo "${TARGET_TOPOLOGY}" + virtual_lan_start + ;; + *) + virtual_lan_usage + exit 1 + esac + ;; + + *) + virtual_lan_usage + exit 1 +esac + |