├── LICENCE ├── README.md ├── fold └── utils ├── eui-64 ├── exp6 ├── lamac ├── mcmac4 ├── mcmac6 ├── solip6 └── solmac /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 David Halls 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fold 2 | 3 | **Note: I'm no longer maintaining this project. Let me know if you wish to contribute.** 4 | 5 | Run virtual machines on a virtual network created by [Weave](https://github.com/zettio/weave). 6 | 7 | - Requires Weave (of course). 8 | - Requires [my fork of nfdhcpd](https://github.com/davedoesdev/nfdhcpd) in order to provide each VM with address and configuration data. 9 | - Like Weave each subnet is fully isolated — Fold sets up the necessary firewall rules. 10 | - Supports custom configuration data per VM using DNS TXT records. Useful for service discovery in multi-VM applications. 11 | - Mix docker containers with VMs - they can talk to each other over the same Weave network. 12 | - Interoperates with weaveDNS: VMs can lookup Weave records and containers can lookup Fold records. 13 | - Full IPv6 support. 14 | - Supports [KVM](http://www.linux-kvm.org/page/Main_Page) and [Rumprun](https://github.com/rumpkernel/rumprun) for lightweight VMs. 15 | 16 | The motivation for Fold is to support applications you don't trust enough to run in containers. For example, multi-tenant environments or when you've pulled in many dependencies and haven't audited all the third party modules your application uses. 17 | 18 | # Usage 19 | 20 | ## Setting up Weave network 21 | 22 | You need to create a Weave network (`weave launch`) before running Fold. Please see the [Weave documentation](https://github.com/zettio/weave) for details. 23 | 24 | Fold supports Weave [automatic IP address management (IPAM)](http://docs.weave.works/weave/latest_release/ipam.html) and [mixed automatic and manual allocation](http://docs.weave.works/weave/latest_release/ipam.html#manual). 25 | 26 | When using IPAM, allocate an IP address using: 27 | 28 | ```shell 29 | fold -i -4 auto [net: | net:default] 30 | ``` 31 | 32 | You must supply an interface name — Weave will assign the address to this name. Supply a CIDR if you don't want to use Weave's default subnet. The allocated IP address will be written to standard output. 33 | 34 | To release the IP address later, after running your VM, you can use: 35 | 36 | ```shell 37 | fold -i -4 release 38 | ``` 39 | 40 | When using mixed allocation, give your VMs IP addresses from the manual allocation range. 41 | 42 | If you want your Weave containers to be able to make DNS queries against Fold, use the Docker `--dns` option when launching your containers. For example, if you're going to run a VM with IP address `10.0.1.100` and want to make DNS queries against it then use `docker run --dns=10.0.1.100 ...` 43 | 44 | ## Running VMs using Fold 45 | 46 | Once you've setup your Weave network, use the `fold` command to run virtual machines on the network: 47 | 48 | ```shell 49 | fold [-i ] 50 | [-4 /] 51 | [-6 ] 52 | [-s] 53 | [-m ]... 54 | [-k ] 55 | [-d ] 56 | [-b ] 57 | [-a ] 58 | [-A ] 59 | 60 | kvm|qemu-system-* [...] 61 | ``` 62 | 63 | You should supply at least one of `-4` or `-6`. 64 | 65 | **`-i`** names the interface created for the VM and attached to the Weave network bridge. If you don't supply one then Fold makes a name up for you. If you're using IPAM then use the same name you used to allocate the IP address. 66 | 67 | **`-4`** gives the VM an IPv4 address and subnet on the Weave network. For example, `-4 10.0.1.100/24`. The VM will be able to communicate with other VMs on the same subnet. If you're using IPAM, use the IP allocated to the interface name. 68 | 69 | **`-6`** gives the VM an IPv6 address and prefix on the Weave network. For example, `-6 fde5:824d:d315:3bb1::/64`. The VM will be able to communicate with other VMs with the same prefix. Your VM's guest OS is assumed to be using [Modified EUI-64](http://tools.ietf.org/html/rfc4291#section-2.5.1), unless you specify the `-s` or `-k` options. 70 | 71 | **`-s`** sets the VM's IPv6 address to the full 128-bit value you specified with `-6` (i.e. with the prefix specifier removed). 72 | 73 | **`-m`** allows the VM to receive IPv4 or IPv6 multicast packets for a given address. You can repeat `-m` more than once, for example `-m 239.1.2.3 -m ff3e::4321:1234`. 74 | 75 | **`-k`** specifies that the VM should use an IPv6 [RFC 7217](https://tools.ietf.org/html/rfc7217) stable privacy address. Fold uses [rdiscd](https://github.com/AGWA/rdiscd) to generate the address. `rdiscd-mkaddress` should be available in your `PATH`. 76 | 77 | The argument to `-k` is the file containing the secret key used to generate the stable privacy address. Fold puts the stable privacy address into a file called `interface-id` on a temporary ext2fs disk image. The path to the image file will be substituted for `_rdiscd_img_file_` in the rest of the arguments. For example: 78 | 79 | ```shell 80 | fold ... -k keyfile ... kvm -fda _rdiscd_img_file_ 81 | ``` 82 | 83 | Note that Fold doesn't support IPv6 [RFC 4941](http://tools.ietf.org/html/rfc4941) temporary addresses so you should disable these in your VM's guest operating system. 84 | 85 | **`-d`** specifies the directory in which to write the file containing the stable privacy address (only if `-k` is specified). Defaults to the current directory. 86 | 87 | **`-b`** specifies a binding file containing configuration data for `nfdhcpd`. It will be used by `nfdhcpd` to supply information such as a hostname and DNS address and TXT records to the VM's guest OS. Please see the [nfdhcpd documentation](https://github.com/davedoesdev/nfdhcpd) for more information. Here's an example: 88 | 89 | ```ini 90 | HOSTNAME=test 91 | GATEWAY=10.0.1.90 92 | GATEWAY_MAC=7a:f4:96:e0:1c:a0 93 | GATEWAY6=fde5:824d:d315:3bb1::91 94 | GATEWAY6_MAC=7e:b7:70:3b:81:77 95 | NAMESERVERS=10.0.1.50 96 | NAMESERVERS6=fde5:824d:d315:3bb1::1 97 | ADDRESS:database.=10.0.1.1 98 | ADDRESS6:database.=fde5:824d:d315:3bb1::9 99 | TXT:table.=Users 100 | DNS_NAMESERVERS=172.17.42.1 101 | ``` 102 | 103 | Fold will add `IPADDR`, `SUBNET`, `PREFIX`, `IP6ADDR` and `BRIDGE` to the settings in your binding file. 104 | 105 | Note that if you define an IPv4 gateway, Fold requires a setting which `nfdhcpd` doesn't use: `GATEWAY_MAC`. Fold needs the MAC of your gateway in order to make sure traffic coming in and out of the subnet (or prefix for IPv6) goes via the gateway only. 106 | 107 | One way to get a gateway on your Weave network is to use [Weave host network integration](http://docs.weave.works/weave/latest_release/features.html#host-network-integration). Use `weave expose` to get the gateway IP address and `weave ps weave:expose` to get the gateway MAC. 108 | 109 | If you want your VM to be able to make queries against weaveDNS, you need to set `DNS_NAMESERVERS` to the IP address of the _Docker_ bridge device (usually `docker0`). Use `ip addr show dev docker0` or `ifconfig docker0` and parse the output to find the IP address. For example: 110 | 111 | ```shell 112 | ifconfig docker0 | grep 'inet addr:' | cut -d: -f2 | awk '{print $1}' 113 | ``` 114 | 115 | **`-a`** specifies the `iptables` action to take for packets outside the subnet coming from or going to the VM's IP address (via the gateway, if you defined one). The default is `-a "-j RETURN"` (resume with non-Fold processing) but you can use `-a "-g ..."` or `-a "-j ..."` to continue processing using a chain you've defined. 116 | 117 | **`-A`** does the same as `-a` but for `ip6tables` and IPv6 packets. 118 | 119 | **``** is a (mandatory) MAC address to give the VM. Note you can use the `utils/lamac` script to generate a random [locally administered address](http://en.wikipedia.org/wiki/MAC_address#Address_details). 120 | 121 | **`...`** should contain arguments necessary to load your VM, for example: 122 | - `-hda disk.qcow2` (KVM) 123 | - `-kernel myrumpkernel.bin -append '{"net": {"if": "vioif0",, "type": "inet",, "method":"dhcp"},, "cmdline": "myapp"}'` (Rumprun). 124 | 125 | ## Environment variables 126 | 127 | Fold uses `iptables`, `ip6tables` and `ebtables`. To change how Fold invokes these commands, set the `IPTABLES`, `IP6TABLES` and `EBTABLES` environment variables respectively. For example, to support concurrent use: 128 | 129 | ```shell 130 | IPTABLES='iptables --wait' IP6TABLES='ip6tables --wait' EBTABLES='ebtables --concurrent' fold ... 131 | ``` 132 | 133 | By default, Fold expects to find the global `nfdhcpd` configuration file at `/etc/nfdhcpd/nfdhcpd.conf`. You can override this by setting `NFDHCPD_CFG`. 134 | 135 | # Examples 136 | 137 | Run a Ubuntu VM on the Weave network, with IPv4 and IPv6 addresses (IPv6 using EUI-64): 138 | 139 | ```shell 140 | fold -4 10.0.1.100/24 -6 fde5:824d:d315:3bb1::/64 -b test-binding 52:54:00:12:34:56 kvm -hda ubuntu.qcow2 141 | ``` 142 | 143 | Run a Ubuntu VM on the Weave network, with IPv4 and IPv6 unicast and multicast addresses (IPv6 unicast address using stable privacy): 144 | 145 | ```shell 146 | fold -4 10.0.1.100/24 -6 fde5:824d:d315:3bb1::/64 -k keyfile -m 239.1.2.3 -b test-binding 52:54:00:12:34:56 kvm -hda ubuntu.qcow2 -fda _rdiscd_img_file_ 147 | ``` 148 | 149 | Run a Rumprun kernel on a Weave network (10.9.200.1/16): 150 | 151 | ```shell 152 | fold -4 10.9.200.1/16 52:54:00:12:34:56 kvm -kernel rumprun-packages/nodejs/build-4.3.0/out/Release/node-hello-world.bin -append '{"net": {"if": "vioif0",, "type": "inet",, "method":"dhcp"},, "cmdline": "node"}' -m 256 153 | ``` 154 | -------------------------------------------------------------------------------- /fold: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | BRIDGE=weave 5 | WEAVE_CONTAINER_NAME=weave 6 | WEAVE_HTTP_PORT=6784 7 | NFDHCPD_CFG="${NFDHCPD_CFG:-/etc/nfdhcpd/nfdhcpd.conf}" 8 | MTU=16384 # max TAP MTU 9 | let "MARK_GATEWAY=1<<0" 10 | let "MARK_GATEWAY6=1<<1" 11 | UTILS="$(dirname "$0")/utils" 12 | IPTABLES="${IPTABLES:-iptables}" 13 | IP6TABLES="${IP6TABLES:-ip6tables}" 14 | EBTABLES="${EBTABLES:-ebtables}" 15 | 16 | usage() { 17 | echo "Usage:" 18 | echo "fold -i -4 auto [net: | net:default]" 19 | echo "fold -i -4 release" 20 | echo "fold [-i ]" 21 | echo " [-4 /] [-6 ] [-s] [-m ]..." 22 | echo " [-k ] [-d ]" 23 | echo " [-b ]" 24 | echo " [-a ] [-A ]" 25 | echo " kvm|qemu-system-* ..." 26 | exit 1 27 | } 28 | 29 | [ "$(id -u)" = 0 ] || { 30 | echo "fold must be run as 'root'" >&2 31 | exit 1 32 | } 33 | 34 | unset IPSUB PREFIX PREFIX_AS_ADDR KEYFILE RDISCD_IMG_FILE TAP_IFNAME 35 | RDISCD_IMG_DIR=. 36 | MULTI4=() 37 | MULTI6=() 38 | NFDHCPD_BINDING_IN=/dev/null 39 | GATEWAY_ACTION="-j RETURN" 40 | GATEWAY6_ACTION="-j RETURN" 41 | while getopts 4:6:sm:k:d:b:i:a:A: opt 42 | do 43 | case $opt in 44 | 4) 45 | IPSUB="$OPTARG" 46 | ;; 47 | 6) 48 | PREFIX="$OPTARG" 49 | ;; 50 | s) 51 | PREFIX_AS_ADDR=1 52 | ;; 53 | m) 54 | if [[ "$OPTARG" == *.* ]]; then 55 | MULTI4=("${MULTI4[@]}" "$OPTARG") 56 | else 57 | MULTI6=("${MULTI6[@]}" "$OPTARG") 58 | fi 59 | ;; 60 | k) 61 | KEYFILE="$OPTARG" 62 | ;; 63 | d) 64 | RDISCD_IMG_DIR="$OPTARG" 65 | ;; 66 | b) 67 | NFDHCPD_BINDING_IN="$OPTARG" 68 | ;; 69 | i) 70 | TAP_IFNAME="$OPTARG" 71 | ;; 72 | a) 73 | GATEWAY_ACTION="$OPTARG" 74 | ;; 75 | A) 76 | GATEWAY6_ACTION="$OPTARG" 77 | ;; 78 | *) 79 | usage 80 | ;; 81 | esac 82 | done 83 | 84 | shift $((OPTIND-1)) 85 | 86 | # IPAM functions taken from weave script 87 | 88 | IP_REGEXP="[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" 89 | CIDR_REGEXP="$IP_REGEXP/[0-9]{1,2}" 90 | 91 | is_cidr() { 92 | echo "$1" | grep -E "^$CIDR_REGEXP$" >/dev/null 93 | } 94 | 95 | container_ip() { 96 | if ! status=$(docker inspect --format='{{.State.Running}} {{.NetworkSettings.IPAddress}}' $1 2>/dev/null) ; then 97 | echo "$2" >&2 98 | return 1 99 | fi 100 | case "$status" in 101 | "true ") 102 | echo "$1 container has no IP address; is Docker networking enabled?" >&2 103 | return 1 104 | ;; 105 | true*) 106 | CONTAINER_IP="${status#true }" 107 | ;; 108 | *) 109 | echo "$3" >&2 110 | return 1 111 | ;; 112 | esac 113 | } 114 | 115 | http_call_ip() { 116 | ip="$1" 117 | port="$2" 118 | http_verb="$3" 119 | url="$4" 120 | shift 4 121 | curl --connect-timeout 3 -s -S -X $http_verb "$@" http://$ip:$port$url 122 | } 123 | 124 | # Call url $4 with http verb $3 on container $1 at port $2 125 | http_call() { 126 | HTTP_CALL_CONTAINER=$1 127 | container_ip $HTTP_CALL_CONTAINER \ 128 | "$HTTP_CALL_CONTAINER container is not present. Have you launched it?" \ 129 | "$HTTP_CALL_CONTAINER container is not running." \ 130 | || return 1 131 | shift 1 132 | if ! http_call_ip $CONTAINER_IP "$@" ; then 133 | echo "Call to $HTTP_CALL_CONTAINER failed." >&2 134 | return 1 135 | fi 136 | } 137 | 138 | if [ "$IPSUB" = auto ]; then 139 | [ -n "$TAP_IFNAME" -a $# -le 1 ] || usage 140 | if [ $# -eq 0 -o "$1" = net:default ]; then 141 | IPAM_URL="/ip/$TAP_IFNAME" 142 | else 143 | IPAM_URL="/ip/$TAP_IFNAME/${1#net:}" 144 | fi 145 | if ! CIDR="$(http_call $WEAVE_CONTAINER_NAME $WEAVE_HTTP_PORT POST "$IPAM_URL")"; then 146 | exit 1 147 | fi 148 | if [ "$CIDR" = "404 page not found" ] ; then 149 | echo "IP address allocation must be enabled to use 'net:'" >&2 150 | exit 1 151 | fi 152 | if ! is_cidr "$CIDR" ; then 153 | echo "$CIDR" >&2 154 | exit 1 155 | fi 156 | echo "$CIDR" 157 | exit 158 | fi 159 | 160 | if [ "$IPSUB" = release ]; then 161 | [ -n "$TAP_IFNAME" -a $# -eq 0 ] || usage 162 | http_call $WEAVE_CONTAINER_NAME $WEAVE_HTTP_PORT DELETE "/ip/$TAP_IFNAME" 163 | exit 164 | fi 165 | 166 | TAP_IFNAME="${TAP_IFNAME:-vethfotp$$}" 167 | NFDHCPD_BINDING_OUT="/var/lib/nfdhcpd/$TAP_IFNAME" 168 | 169 | [ $# -gt 1 ] || usage 170 | 171 | MACADDR="$1" 172 | COMMAND="$2" 173 | shift 2 174 | 175 | trim() { 176 | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' "$@" 177 | } 178 | 179 | config() { 180 | grep -i "^$1 *=" $2 | sed 's/^[^=]*=//' | sed 's/#.*$//' | trim 181 | } 182 | 183 | config1() { 184 | config "$1" "$2" | sed 's/,.*$//' | trim 185 | } 186 | 187 | run_prog() { 188 | local user="${SUDO_USER:-root}" 189 | if command -v sudo >& /dev/null; then 190 | sudo -u "$user" "$@" 191 | else 192 | su --preserve-environment -l -c 'exec "$0" "$@"' "$user" -- "$@" 193 | fi 194 | } 195 | 196 | DHCP_QUEUE="$(config dhcp_queue "$NFDHCPD_CFG")" 197 | DHCP6_QUEUE="$(config dhcp6_queue "$NFDHCPD_CFG")" 198 | RS_QUEUE="$(config rs_queue "$NFDHCPD_CFG")" 199 | NS_QUEUE="$(config ns_queue "$NFDHCPD_CFG")" 200 | DNS_QUEUE="$(config dns_queue "$NFDHCPD_CFG")" 201 | DNS6_QUEUE="$(config dns6_queue "$NFDHCPD_CFG")" 202 | NOTIFY_QUEUE="$(config notify_queue "$NFDHCPD_CFG")" 203 | NOTIFY6_QUEUE="$(config notify6_queue "$NFDHCPD_CFG")" 204 | NAMESERVER="$(config1 nameservers "$NFDHCPD_BINDING_IN")" 205 | GATEWAY="$(config gateway "$NFDHCPD_BINDING_IN")" 206 | GATEWAY_MAC="$(config gateway_mac "$NFDHCPD_BINDING_IN")" 207 | GATEWAY6="$(config gateway6 "$NFDHCPD_BINDING_IN")" 208 | GATEWAY6_MAC="$(config gateway6_mac "$NFDHCPD_BINDING_IN")" 209 | 210 | if [ "$IPSUB" ]; then 211 | # extract the IP address from an ipaddr/subnet spec 212 | IFS=/ read -a ipsub <<< "$IPSUB" 213 | IPADDR="${ipsub[0]}" 214 | 215 | # make a zero-ending subnet mask (CIDR) from an ipaddr/subnet spec 216 | IFS=. read -a ipaddr <<< "$IPADDR" 217 | ipnum=$(((ipaddr[0] << 24) + (ipaddr[1] << 16) + (ipaddr[2] << 8) + (ipaddr[3]))) 218 | ipnum=$((ipnum & ~(2 ** (32 - ipsub[1]) - 1))) 219 | SUBNET=$((ipnum >> 24 & 255)).$((ipnum >> 16 & 255)).$((ipnum >> 8 & 255)).$((ipnum & 255))/${ipsub[1]} 220 | fi 221 | 222 | if [ "$PREFIX" ]; then 223 | if [ "$KEYFILE" ]; then 224 | # For RFC-7217 (stable privacy addresses), support rdiscd. 225 | # We generate an address using rdiscd-mkaddress here and write it into 226 | # a disk image which we attach to the VM. rdiscd can then pick this up 227 | # in the guest. We could generate a random address here but it's nice 228 | # to be able to know which IPv6 address relates to a MAC address. 229 | IP6ADDR="$(rdiscd-mkaddress -m "$MACADDR" -k "$KEYFILE" "$PREFIX" stable-privacy)" 230 | RDISCD_IMG_FILE="$RDISCD_IMG_DIR/rdiscd_$TAP_IFNAME.img" 231 | run_prog genext2fs -b 1440 "$RDISCD_IMG_FILE" 232 | echo "::$("$UTILS/exp6" "$IP6ADDR" 16 8)" | run_prog e2cp -P 400 - "$RDISCD_IMG_FILE:interface-id" 233 | echo 64 | run_prog e2cp -P 400 - "$RDISCD_IMG_FILE:interface-id-len" 234 | elif [ -n "$PREFIX_AS_ADDR" ]; then 235 | # Use the prefix as the address 236 | IP6ADDR="$("$UTILS/exp6" "${PREFIX%/*}")" 237 | else 238 | # Assume guest uses EUI-64. 239 | IP6ADDR="$("$UTILS/exp6" "$PREFIX" 8):$("$UTILS/eui-64" "$MACADDR")" 240 | fi 241 | # RFC-4941 (privacy extensions) aren't supported since we'd have no way 242 | # to tell nfdhcpd what to use when rewriting neighbour advertisement source 243 | # addresses. Also, allowing any VM to send/receive packets on any address 244 | # isn't desirable - we want to know a VM is only sending traffic on its 245 | # expected address (i.e. it's not impersonating another VM). 246 | fi 247 | 248 | unrule() { 249 | if $IPTABLES -t mangle -L "in$TAP_IFNAME" >& /dev/null; then 250 | $IPTABLES -t mangle -D PREROUTING -m physdev --physdev-in "$TAP_IFNAME" -j "in$TAP_IFNAME" 251 | $IPTABLES -t mangle -F "in$TAP_IFNAME" 252 | $IPTABLES -t mangle -X "in$TAP_IFNAME" 253 | fi 254 | if $IPTABLES -t mangle -L "out$TAP_IFNAME" >& /dev/null; then 255 | $IPTABLES -t mangle -D FORWARD -m physdev --physdev-is-bridged --physdev-out "$TAP_IFNAME" -j "out$TAP_IFNAME" 256 | $IPTABLES -t mangle -F "out$TAP_IFNAME" 257 | $IPTABLES -t mangle -X "out$TAP_IFNAME" 258 | fi 259 | if $IPTABLES -L "in$TAP_IFNAME" >& /dev/null; then 260 | $IPTABLES -D FORWARD -m physdev --physdev-in "$TAP_IFNAME" -j "in$TAP_IFNAME" 261 | $IPTABLES -D INPUT -m physdev --physdev-in "$TAP_IFNAME" -j "in$TAP_IFNAME" 262 | $IPTABLES -F "in$TAP_IFNAME" 263 | $IPTABLES -X "in$TAP_IFNAME" 264 | fi 265 | if $IPTABLES -L "out$TAP_IFNAME" >& /dev/null; then 266 | $IPTABLES -D FORWARD -m physdev --physdev-is-bridged --physdev-out "$TAP_IFNAME" -j "out$TAP_IFNAME" 267 | $IPTABLES -D FORWARD -o "$BRIDGE" -d "$IPADDR" -j "out$TAP_IFNAME" 268 | $IPTABLES -D OUTPUT -o "$BRIDGE" -d "$IPADDR" -j "out$TAP_IFNAME" 269 | $IPTABLES -F "out$TAP_IFNAME" 270 | $IPTABLES -X "out$TAP_IFNAME" 271 | fi 272 | if $IP6TABLES -t mangle -L "in$TAP_IFNAME" >& /dev/null; then 273 | $IP6TABLES -t mangle -D PREROUTING -m physdev --physdev-in "$TAP_IFNAME" -j "in$TAP_IFNAME" 274 | $IP6TABLES -t mangle -F "in$TAP_IFNAME" 275 | $IP6TABLES -t mangle -X "in$TAP_IFNAME" 276 | fi 277 | if $IP6TABLES -t mangle -L "out$TAP_IFNAME" >& /dev/null; then 278 | $IP6TABLES -t mangle -D FORWARD -m physdev --physdev-is-bridged --physdev-out "$TAP_IFNAME" -j "out$TAP_IFNAME" 279 | $IP6TABLES -t mangle -F "out$TAP_IFNAME" 280 | $IP6TABLES -t mangle -X "out$TAP_IFNAME" 281 | fi 282 | if $IP6TABLES -L "in$TAP_IFNAME" >& /dev/null; then 283 | $IP6TABLES -D INPUT -m physdev --physdev-in "$TAP_IFNAME" -j "in$TAP_IFNAME" 284 | $IP6TABLES -D FORWARD -m physdev --physdev-in "$TAP_IFNAME" -j "in$TAP_IFNAME" 285 | $IP6TABLES -F "in$TAP_IFNAME" 286 | $IP6TABLES -X "in$TAP_IFNAME" 287 | fi 288 | if $IP6TABLES -L "out$TAP_IFNAME" >& /dev/null; then 289 | $IP6TABLES -D FORWARD -m physdev --physdev-is-bridged --physdev-out "$TAP_IFNAME" -j "out$TAP_IFNAME" 290 | $IP6TABLES -D FORWARD -o "$BRIDGE" -d "$IP6ADDR" -j "out$TAP_IFNAME" 291 | $IP6TABLES -D OUTPUT -o "$BRIDGE" -d "$IP6ADDR" -j "out$TAP_IFNAME" 292 | $IP6TABLES -F "out$TAP_IFNAME" 293 | $IP6TABLES -X "out$TAP_IFNAME" 294 | fi 295 | if $EBTABLES -t nat -L "in$TAP_IFNAME" >& /dev/null; then 296 | $EBTABLES -t nat -D PREROUTING -i "$TAP_IFNAME" -j "in$TAP_IFNAME" 297 | $EBTABLES -t nat -F "in$TAP_IFNAME" 298 | $EBTABLES -t nat -X "in$TAP_IFNAME" 299 | fi 300 | #$EBTABLES -D FORWARD --log >& /dev/null || true 301 | if $EBTABLES -L "in$TAP_IFNAME" >& /dev/null; then 302 | $EBTABLES -D FORWARD -i "$TAP_IFNAME" -j "in$TAP_IFNAME" 303 | $EBTABLES -F "in$TAP_IFNAME" 304 | $EBTABLES -X "in$TAP_IFNAME" 305 | fi 306 | if $EBTABLES -L "out$TAP_IFNAME" >& /dev/null; then 307 | $EBTABLES -D FORWARD -o "$TAP_IFNAME" -j "out$TAP_IFNAME" 308 | $EBTABLES -F "out$TAP_IFNAME" 309 | $EBTABLES -X "out$TAP_IFNAME" 310 | fi 311 | } 312 | 313 | rule() { 314 | $EBTABLES -t nat -N "in$TAP_IFNAME" -P RETURN 315 | $EBTABLES -t nat -I PREROUTING -i "$TAP_IFNAME" -j "in$TAP_IFNAME" 316 | 317 | if [ "$IPSUB" ]; then 318 | $IPTABLES -t mangle -N "in$TAP_IFNAME" 319 | $IPTABLES -t mangle -I PREROUTING -m physdev --physdev-in "$TAP_IFNAME" -j "in$TAP_IFNAME" 320 | $IPTABLES -t mangle -A "in$TAP_IFNAME" -p udp --dport bootps -j NFQUEUE --queue-num "$DHCP_QUEUE" 321 | $IPTABLES -t mangle -A "in$TAP_IFNAME" -p udp --dport domain -j NFQUEUE --queue-num "$DNS_QUEUE" 322 | 323 | $IPTABLES -t mangle -N "out$TAP_IFNAME" 324 | $IPTABLES -t mangle -I FORWARD -m physdev --physdev-is-bridged --physdev-out "$TAP_IFNAME" -j "out$TAP_IFNAME" 325 | $IPTABLES -t mangle -A "out$TAP_IFNAME" -p udp --dport domain -j NFQUEUE --queue-num "$DNS_QUEUE" 326 | 327 | #$IPTABLES -t mangle -L 328 | 329 | $IPTABLES -N "in$TAP_IFNAME" 330 | $IPTABLES -I FORWARD -m physdev --physdev-in "$TAP_IFNAME" -j "in$TAP_IFNAME" 331 | $IPTABLES -I INPUT -m physdev --physdev-in "$TAP_IFNAME" -j "in$TAP_IFNAME" 332 | if [ "$GATEWAY_MAC" ]; then 333 | $IPTABLES -A "in$TAP_IFNAME" -s "$IPADDR" -m mark --mark "$MARK_GATEWAY/$MARK_GATEWAY" $GATEWAY_ACTION 334 | fi 335 | $IPTABLES -A "in$TAP_IFNAME" -s "$IPADDR" -d "$SUBNET" -j RETURN 336 | for addr in "${MULTI4[@]}"; do 337 | $IPTABLES -A "in$TAP_IFNAME" -s "$IPADDR" -d "$addr" -j RETURN 338 | done 339 | $IPTABLES -A "in$TAP_IFNAME" -j REJECT 340 | 341 | $IPTABLES -N "out$TAP_IFNAME" 342 | $IPTABLES -I FORWARD -m physdev --physdev-is-bridged --physdev-out "$TAP_IFNAME" -j "out$TAP_IFNAME" 343 | $IPTABLES -I FORWARD -o "$BRIDGE" -d "$IPADDR" -j "out$TAP_IFNAME" 344 | $IPTABLES -I OUTPUT -o "$BRIDGE" -d "$IPADDR" -j "out$TAP_IFNAME" 345 | if [ "$GATEWAY" ]; then 346 | $IPTABLES -A "out$TAP_IFNAME" ! -s "$SUBNET" -d "$IPADDR" $GATEWAY_ACTION 347 | $IPTABLES -A "out$TAP_IFNAME" -s "$GATEWAY" -d "$IPADDR" $GATEWAY_ACTION 348 | fi 349 | $IPTABLES -A "out$TAP_IFNAME" -s "$SUBNET" -d "$IPADDR" -j RETURN 350 | for addr in "${MULTI4[@]}"; do 351 | $IPTABLES -A "out$TAP_IFNAME" -s "$SUBNET" -d "$addr" -j RETURN 352 | done 353 | $IPTABLES -A "out$TAP_IFNAME" -j REJECT 354 | #$IPTABLES -L 355 | 356 | if [ "$NAMESERVER" ]; then 357 | $EBTABLES -t nat -A "in$TAP_IFNAME" -p arp --arp-opcode request --arp-ip-dst "$NAMESERVER" -j arpreply --arpreply-mac "$MACADDR" 358 | fi 359 | if [ "$GATEWAY_MAC" ]; then 360 | $EBTABLES -t nat -A "in$TAP_IFNAME" -d "$GATEWAY_MAC" -j mark --mark-or "$MARK_GATEWAY" --mark-target CONTINUE 361 | fi 362 | #$EBTABLES -t nat -L 363 | fi 364 | 365 | if [ "$PREFIX" ]; then 366 | $IP6TABLES -t mangle -N "in$TAP_IFNAME" 367 | $IP6TABLES -t mangle -I PREROUTING -m physdev --physdev-in "$TAP_IFNAME" -j "in$TAP_IFNAME" 368 | $IP6TABLES -t mangle -A "in$TAP_IFNAME" -p udp --dport dhcpv6-server -j NFQUEUE --queue-num "$DHCP6_QUEUE" 369 | $IP6TABLES -t mangle -A "in$TAP_IFNAME" -p udp --dport domain -j NFQUEUE --queue-num "$DNS6_QUEUE" 370 | $IP6TABLES -t mangle -A "in$TAP_IFNAME" -p ipv6-icmp --icmpv6-type router-solicitation -j NFQUEUE --queue-num "$RS_QUEUE" 371 | $IP6TABLES -t mangle -A "in$TAP_IFNAME" -p ipv6-icmp --icmpv6-type neighbour-solicitation -j NFQUEUE --queue-num "$NS_QUEUE" 372 | 373 | $IP6TABLES -t mangle -N "out$TAP_IFNAME" 374 | $IP6TABLES -t mangle -I FORWARD -m physdev --physdev-is-bridged --physdev-out "$TAP_IFNAME" -j "out$TAP_IFNAME" 375 | $IP6TABLES -t mangle -A "out$TAP_IFNAME" -p udp --dport domain -j NFQUEUE --queue-num "$DNS6_QUEUE" 376 | 377 | #$IP6TABLES -t mangle -L 378 | 379 | $IP6TABLES -N "in$TAP_IFNAME" 380 | $IP6TABLES -I FORWARD -m physdev --physdev-in "$TAP_IFNAME" -j "in$TAP_IFNAME" 381 | $IP6TABLES -I INPUT -m physdev --physdev-in "$TAP_IFNAME" -j "in$TAP_IFNAME" 382 | if [ "$GATEWAY6_MAC" ]; then 383 | $IP6TABLES -A "in$TAP_IFNAME" -s "$IP6ADDR" -m mark --mark "$MARK_GATEWAY6/$MARK_GATEWAY6" $GATEWAY6_ACTION 384 | fi 385 | $IP6TABLES -A "in$TAP_IFNAME" -s "$IP6ADDR" -d "$PREFIX" -j RETURN 386 | for addr in "${MULTI6[@]}"; do 387 | $IP6TABLES -A "in$TAP_IFNAME" -s "$IP6ADDR" -d "$addr" -j RETURN 388 | done 389 | # Allow packets to solicited-node multicast addresses (for neighbour 390 | # solicitations). nfdhcpd checks if the request is for the allocated 391 | # prefix (and only intercepts if it's not). nfdhcp also sets the source 392 | # address to the non-link local address. 393 | # Note that we expect neighbour advertisements to have non-link local 394 | # source and destination. 395 | $IP6TABLES -A "in$TAP_IFNAME" -s "$IP6ADDR" -d ff02:0:0:0:0:1:ff00::/104 -p ipv6-icmp --icmpv6-type neighbour-solicitation -j RETURN 396 | $IP6TABLES -A "in$TAP_IFNAME" -j REJECT 397 | 398 | $IP6TABLES -N "out$TAP_IFNAME" 399 | $IP6TABLES -I FORWARD -m physdev --physdev-is-bridged --physdev-out "$TAP_IFNAME" -j "out$TAP_IFNAME" 400 | $IP6TABLES -I FORWARD -o "$BRIDGE" -d "$IP6ADDR" -j "out$TAP_IFNAME" 401 | $IP6TABLES -I OUTPUT -o "$BRIDGE" -d "$IP6ADDR" -j "out$TAP_IFNAME" 402 | if [ "$GATEWAY6_MAC" ]; then 403 | $IP6TABLES -A "out$TAP_IFNAME" ! -s "$PREFIX" -d "$IP6ADDR" $GATEWAY6_ACTION 404 | $IP6TABLES -A "out$TAP_IFNAME" -s "$GATEWAY6" -d "$IP6ADDR" $GATEWAY6_ACTION 405 | fi 406 | $IP6TABLES -A "out$TAP_IFNAME" -s "$PREFIX" -d "$IP6ADDR" -j RETURN 407 | for addr in "${MULTI6[@]}"; do 408 | $IP6TABLES -A "out$TAP_IFNAME" -s "$PREFIX" -d "$addr" -j RETURN 409 | done 410 | # Allow packets to our solicited-node multicast address (for neighbour 411 | # solicitations). 412 | # Note that we expect neighbour advertisements to have non-link local 413 | # source and destination. 414 | $IP6TABLES -A "out$TAP_IFNAME" -s "$PREFIX" -d "$("$UTILS/solip6" "$IP6ADDR")" -p ipv6-icmp --icmpv6-type neighbour-solicitation -j RETURN 415 | $IP6TABLES -A "out$TAP_IFNAME" -j REJECT 416 | #$IP6TABLES -L 417 | 418 | if [ "$GATEWAY6_MAC" ]; then 419 | $EBTABLES -t nat -A "in$TAP_IFNAME" -d "$GATEWAY6_MAC" -j mark --mark-or "$MARK_GATEWAY6" --mark-target CONTINUE 420 | fi 421 | fi 422 | 423 | NOTIFY_PORT="$(config notify_port "$NFDHCPD_BINDING_IN")" 424 | if [ "$NOTIFY_PORT" ]; then 425 | if [ "$IPSUB" ]; then 426 | NOTIFY_IP="$(config notify_ip "$NFDHCPD_BINDING_IN")" 427 | if [ "$NOTIFY_IP" ]; then 428 | $IPTABLES -t mangle -A "in$TAP_IFNAME" -p udp -d "$NOTIFY_IP" --dport "$NOTIFY_PORT" -j NFQUEUE --queue-num "$NOTIFY_QUEUE" 429 | $IPTABLES -t mangle -A "in$TAP_IFNAME" -p udp --dport "$NOTIFY_PORT" -j DROP 430 | $IPTABLES -t mangle -A "in$TAP_IFNAME" -p tcp --dport "$NOTIFY_PORT" -j DROP 431 | $IPTABLES -I "out$TAP_IFNAME" -p udp --dport "$NOTIFY_PORT" -j REJECT 432 | $IPTABLES -I "out$TAP_IFNAME" -p tcp --dport "$NOTIFY_PORT" -j REJECT 433 | $EBTABLES -t nat -A "in$TAP_IFNAME" -p arp --arp-opcode request --arp-ip-dst "$NOTIFY_IP" -j arpreply --arpreply-mac "$MACADDR" 434 | fi 435 | fi 436 | if [ "$PREFIX" ]; then 437 | NOTIFY_IP6="$(config notify_ip6 "$NFDHCPD_BINDING_IN")" 438 | if [ "$NOTIFY_IP6" ]; then 439 | $IP6TABLES -t mangle -A "in$TAP_IFNAME" -p udp -d "$NOTIFY_IP6" --dport "$NOTIFY_PORT" -j NFQUEUE --queue-num "$NOTIFY6_QUEUE" 440 | $IP6TABLES -t mangle -A "in$TAP_IFNAME" -p udp --dport "$NOTIFY_PORT" -j DROP 441 | $IP6TABLES -t mangle -A "in$TAP_IFNAME" -p tcp --dport "$NOTIFY_PORT" -j DROP 442 | $IP6TABLES -I "out$TAP_IFNAME" -p udp --dport "$NOTIFY_PORT" -j REJECT 443 | $IP6TABLES -I "out$TAP_IFNAME" -p tcp --dport "$NOTIFY_PORT" -j REJECT 444 | fi 445 | fi 446 | fi 447 | 448 | #$EBTABLES -I FORWARD --log 449 | $EBTABLES -N "in$TAP_IFNAME" -P DROP 450 | $EBTABLES -A FORWARD -i "$TAP_IFNAME" -j "in$TAP_IFNAME" 451 | # Stop any packets not from allocated MAC address 452 | $EBTABLES -A "in$TAP_IFNAME" -s ! "$MACADDR" -j DROP 453 | if [ "$IPSUB" ]; then 454 | # Allow ARP packets from this IP address to subnet 455 | $EBTABLES -A "in$TAP_IFNAME" -p arp --arp-ip-src "$IPADDR" --arp-ip-dst "$SUBNET" -j RETURN 456 | # Allow IPv4 457 | $EBTABLES -A "in$TAP_IFNAME" -p ipv4 -j RETURN 458 | fi 459 | if [ "$PREFIX" ]; then 460 | # Allow IPv6 461 | $EBTABLES -A "in$TAP_IFNAME" -p ipv6 -j RETURN 462 | fi 463 | 464 | $EBTABLES -N "out$TAP_IFNAME" -P DROP 465 | $EBTABLES -A FORWARD -o "$TAP_IFNAME" -j "out$TAP_IFNAME" 466 | if [ "$IPSUB" ]; then 467 | # Allow ARP requests for this IP address from subnet 468 | $EBTABLES -A "out$TAP_IFNAME" -p arp --arp-opcode request --arp-ip-src "$SUBNET" --arp-ip-dst "$IPADDR" -j RETURN 469 | # Allow IPv4 multicast 470 | for addr in "${MULTI4[@]}"; do 471 | $EBTABLES -A "out$TAP_IFNAME" -d "$("$UTILS/mcmac4" "$addr")" -j RETURN 472 | done 473 | fi 474 | if [ "$PREFIX" ]; then 475 | # Allow solicited-node multicast requests 476 | $EBTABLES -A "out$TAP_IFNAME" -d "$("$UTILS/solmac" "$IP6ADDR")" -j RETURN 477 | # Allow IPv6 multicast 478 | for addr in "${MULTI6[@]}"; do 479 | $EBTABLES -A "out$TAP_IFNAME" -d "$("$UTILS/mcmac6" "$addr")" -j RETURN 480 | done 481 | fi 482 | # Stop any packets not for allocated MAC address 483 | $EBTABLES -A "out$TAP_IFNAME" -d ! "$MACADDR" -j DROP 484 | if [ "$IPSUB" ]; then 485 | # Allow ARP replies to this IP address but only from subnet 486 | $EBTABLES -A "out$TAP_IFNAME" -p arp --arp-opcode reply --arp-ip-src "$SUBNET" --arp-ip-dst "$IPADDR" -j RETURN 487 | # Allow IPv4 488 | $EBTABLES -A "out$TAP_IFNAME" -p ipv4 -j RETURN 489 | fi 490 | if [ "$PREFIX" ]; then 491 | # Allow IPv6 492 | $EBTABLES -A "out$TAP_IFNAME" -p ipv6 -j RETURN 493 | fi 494 | #$EBTABLES -L 495 | } 496 | 497 | untap() { 498 | if ip link show dev "$TAP_IFNAME" >& /dev/null; then 499 | ip link del dev "$TAP_IFNAME" 500 | fi 501 | } 502 | 503 | tap() { 504 | ip tuntap add dev "$TAP_IFNAME" mode tap 505 | ip link set dev "$TAP_IFNAME" mtu "$MTU" 506 | ip link set dev "$TAP_IFNAME" master "$BRIDGE" 507 | ip link set dev "$TAP_IFNAME" up 508 | } 509 | 510 | cleanup() { 511 | trap - EXIT 512 | untap; unrule 513 | rm -f "$NFDHCPD_BINDING_OUT" 514 | [ "$RDISCD_IMG_FILE" ] && run_prog rm -f "$RDISCD_IMG_FILE" 515 | } 516 | 517 | trap cleanup EXIT # bash calls cleanup when exiting due to signals too 518 | 519 | unrule; rule 520 | untap; tap 521 | 522 | ( echo "MAC=$MACADDR" 523 | [ "$IPADDR" ] && echo "IP=$IPADDR" 524 | [ "$SUBNET" ] && echo "SUBNET=$SUBNET" 525 | [ "$PREFIX" ] && echo "SUBNET6=$PREFIX" 526 | [ "$IP6ADDR" ] && echo "IP6=$IP6ADDR" 527 | echo "BRIDGE=$BRIDGE" 528 | echo "MTU=$MTU" 529 | cat "$NFDHCPD_BINDING_IN" ) > "$NFDHCPD_BINDING_OUT" 530 | 531 | args=("${@//_rdiscd_img_file_/$RDISCD_IMG_FILE}") 532 | 533 | case "$COMMAND" in 534 | kvm|qemu-system-*) 535 | run_prog "$COMMAND" -netdev "tap,id=hn0,ifname=$TAP_IFNAME,script=no,downscript=no" -device "virtio-net-pci,netdev=hn0,id=nic1,mac=$MACADDR" "${args[@]}" 536 | ;; 537 | *) 538 | echo "Unknown fold command '$COMMAND'" >&2 539 | usage 540 | ;; 541 | esac 542 | 543 | -------------------------------------------------------------------------------- /utils/eui-64: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # make an EUI-64 address from a MAC-48 address 3 | if test $# -ne 1; then 4 | echo "usage: $0 " 1>&2 5 | exit 1 6 | fi 7 | mac="$(echo "$1" | tr -d : | tr A-Z a-z)" 8 | mac="$(echo "$mac" | head -c 6)fffe$(echo "$mac" | tail -c +7)" 9 | let "b = 0x$(echo "$mac" | head -c 2)" 10 | let "b ^= 2" 11 | printf "%02x" "$b" 12 | echo "$mac" | tail -c +3 | head -c 2 13 | echo -n : 14 | echo "$mac" | tail -c +5 | head -c 4 15 | echo -n : 16 | echo "$mac" | tail -c +9 | head -c 4 17 | echo -n : 18 | echo "$mac" | tail -c +13 19 | -------------------------------------------------------------------------------- /utils/exp6: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # expand an IPv6 address 3 | import argparse, socket, binascii, sys, re 4 | parser = argparse.ArgumentParser() 5 | parser.add_argument("ip6addr", help="IPv6 address") 6 | parser.add_argument("left", help="Number of leftmost bytes to output", type=int, nargs="?", default=16) 7 | parser.add_argument("right", help="Number of rightmost bytes to output", type=int, nargs="?", default=16) 8 | args = parser.parse_args() 9 | ip6addr = args.ip6addr.partition("/") 10 | exp = socket.inet_pton(socket.AF_INET6, ip6addr[0]) 11 | if ip6addr[2]: 12 | prefix = int(ip6addr[2]) 13 | n = long(exp.encode('hex'), 16) 14 | n &= ~(2 ** (128 - prefix) - 1) 15 | exp = ''.join([chr(n >> (i * 8) & 255) for i in xrange(15, -1, -1)]) 16 | hex = binascii.hexlify(exp) 17 | out = hex[:args.left * 2][-args.right * 2:] 18 | if args.right < args.left: 19 | regex = re.compile(r'(.{1,4})(?=(.{4})+)') 20 | else: 21 | regex = re.compile(r'(.{4})(?!$)') 22 | sys.stdout.write(regex.sub(r'\1:', out)) 23 | -------------------------------------------------------------------------------- /utils/lamac: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # generate a random locally-administered MAC address 3 | read -a bytes < <(od -N 6 /dev/urandom -A n -t u1 -v) 4 | let "bytes[0] &= 0xfc" 5 | let "bytes[0] |= 0x2" 6 | for i in "${!bytes[@]}"; do 7 | bytes[$i]=$(printf "%02x" "${bytes[$i]}") 8 | done 9 | IFS=: 10 | echo "${bytes[*]}" 11 | -------------------------------------------------------------------------------- /utils/mcmac4: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # convert an IPv4 address into a mulicast MAC address 3 | import argparse, socket, binascii, sys, re 4 | 5 | regex = re.compile(r'(.{2})(?!$)') 6 | def fmt(n): 7 | exp = ''.join([chr(n >> (i * 8) & 255) for i in xrange(5, -1, -1)]) 8 | hex = binascii.hexlify(exp) 9 | return regex.sub(r'\1:', hex) 10 | 11 | parser = argparse.ArgumentParser() 12 | parser.add_argument("ip4addr", help="IPv4 address") 13 | args = parser.parse_args() 14 | ip4addr = args.ip4addr.partition("/") 15 | b = ip4addr[2] 16 | b = int(b) if b else 32 17 | exp = socket.inet_pton(socket.AF_INET, ip4addr[0]) 18 | n = long(exp.encode('hex'), 16) 19 | n &= (2 ** 23 - 1) 20 | n |= 0x01005e000000 21 | m = ~(2 ** (23 - max(b - 9, 0)) - 1) 22 | n &= m 23 | sys.stdout.write(fmt(n)) 24 | if b < 32: 25 | sys.stdout.write('/') 26 | sys.stdout.write(fmt(m)) 27 | -------------------------------------------------------------------------------- /utils/mcmac6: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # convert an IPv6 address into a mulicast MAC address 3 | import argparse, socket, binascii, sys, re 4 | 5 | regex = re.compile(r'(.{2})(?!$)') 6 | def fmt(n): 7 | exp = ''.join([chr(n >> (i * 8) & 255) for i in xrange(5, -1, -1)]) 8 | hex = binascii.hexlify(exp) 9 | return regex.sub(r'\1:', hex) 10 | 11 | parser = argparse.ArgumentParser() 12 | parser.add_argument("ip6addr", help="IPv6 address") 13 | args = parser.parse_args() 14 | ip6addr = args.ip6addr.partition("/") 15 | b = ip6addr[2] 16 | b = int(b) if b else 128 17 | exp = socket.inet_pton(socket.AF_INET6, ip6addr[0]) 18 | n = long(exp.encode('hex'), 16) 19 | n &= (2 ** 32 - 1) 20 | n |= 0x333300000000 21 | m = ~(2 ** (32 - max(b - 96, 0)) - 1) 22 | n &= m 23 | sys.stdout.write(fmt(n)) 24 | if b < 128: 25 | sys.stdout.write('/') 26 | sys.stdout.write(fmt(m)) 27 | -------------------------------------------------------------------------------- /utils/solip6: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # make solicited-node multicast IPv6 address from IPv6 address 3 | if test $# -ne 1; then 4 | echo "usage: $0 " 1>&2 5 | exit 1 6 | fi 7 | echo -n ff02::1:ff$("$(dirname "$0")/exp6" "$1" 16 3) 8 | -------------------------------------------------------------------------------- /utils/solmac: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # make solicited-node multicast MAC address from IPv6 address 3 | if test $# -ne 1; then 4 | echo "usage: $0 " 1>&2 5 | exit 1 6 | fi 7 | echo -n 33:33:ff:$("$(dirname "$0")/exp6" "$1" 16 3 | sed 's/\(.\{2\}\)$/:\1/') 8 | --------------------------------------------------------------------------------