From 36716dab42031ac42496ca9cd27acdbcd509bf19 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 16 Apr 2024 10:18:00 +0200 Subject: [PATCH] utils: ixll: Add link-local wrappers for ping/ssh/scp --- utils/ixll | 92 +++++++++++++++++++++++++++++++ utils/libll.sh | 146 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100755 utils/ixll create mode 100644 utils/libll.sh diff --git a/utils/ixll b/utils/ixll new file mode 100755 index 00000000..f4121709 --- /dev/null +++ b/utils/ixll @@ -0,0 +1,92 @@ +#!/bin/sh + +set -e + +. $(dirname $(readlink -f "$0"))/libll.sh + +usage() +{ + local me="$(basename $0)" + + cat < [] + +Wrap various existing network facilities such that an interface name +may be supplied in places where a hostname is otherwise expected. + + Options: + + -A + For commands requiring authentication, use password + authentication with username "admin" and password "admin". + + Commands: + + peer + Return the address of the first IPv6 neighbor to respond on + 's local LAN. + + ping + Send ping to all-hosts group, with link-local scope, on , + suppressing loopbacked packets. + + ssh [] + ssh(1) to the neighboring host on . + + scp + scp(1) from to , but any host specified in either + or is assumed to be an interface name, which is + expanded to a neighboring host on that interface. + + ${0} help + Display this message. + + Examples: + + Start interactive ssh(1) session to the neighbor to eth0 + $me ssh eth0 + + Copy /etc/hostname from the neighbor to eth0, using admin/admin + $me -A scp eth0:/etc/hostname /tmp/hostname + +EOF +} + +while getopts "A" opt; do + case ${opt} in + A) + LLSSH_USER=admin + LLSSH_PASS=admin + ;; + esac +done +shift $((OPTIND - 1)) + +if [ $# -lt 1 ]; then + usage && exit 1 +fi + +cmd="$1" +shift + +case "$cmd" in + help) + usage && exit 0 + ;; + peer) + llpeer "$@" + ;; + ping) + llping "$@" + ;; + scp) + llscp "$@" + ;; + ssh) + llssh "$@" + ;; + *) + echo "Unknown command \"$cmd\"" >2 + exit 1 + ;; +esac diff --git a/utils/libll.sh b/utils/libll.sh new file mode 100644 index 00000000..d42f94ab --- /dev/null +++ b/utils/libll.sh @@ -0,0 +1,146 @@ +# Utility functions for communicating with IPv6 neighbors on the local +# LAN + +# Usage: llping +# +# Send ping to all-hosts group, with link-local scope, on , +# suppressing loopbacked packets. +llping() +{ + local iface="$1" + shift + ping -L ff02::1%$iface "$@" +} + + +# Usage: llpeer +# +# Return the address of the first IPv6 neighbor to respond on +# 's local LAN. It is thus typically only useful in scenarios +# where only one neighbor exists +llpeer() +{ + local iface="$1" + shift + llping $iface -c1 "$@" | \ + awk '/bytes from/ { sub(/:$/, "", $4); print($4); exit(0); }' +} + +llssh_expand() +{ + local old_ifs="$IFS" + + local orig="$1" + local fmt="$2" + + local peer= + local user= + local iface= + + IFS=@ + set $1 + IFS="$old_ifs" + case $# in + 1) + user="$LLSSH_USER" + iface="$1" + ;; + 2) + user="$1" + iface="$2" + ;; + *) + echo "Error: Invalid peer \"$orig1\"" >&2 + return 1 + ;; + esac + + if [ -d "/sys/class/net/$iface" ]; then + peer="$(llpeer $iface -w3)" + else + peer="$iface" + fi + + if [ ! "$peer" ]; then + echo "Error: No peer responded on $iface" >&2 + return 1 + fi + + case "$fmt" in + ssh) + ;; + scp) + peer="[$peer]" + ;; + *) + echo "Internal error: Invalid format \"$fmt\"" >&2 + return 1 + ;; + esac + + [ "$user" ] && peer="$user@$peer" + echo $peer +} + +# Usage: llssh [] +# +# ssh(1) to , but if the host matches an existing +# interface name, expand it to a neighboring host on that interface. +llssh() +{ + local remote="$1" + shift + + local peer="$(llssh_expand $remote ssh)" + [ "$peer" ] || return 1 + + local sshpasscmd= + [ "$LLSSH_PASS" ] && sshpasscmd="sshpass -p$LLSSH_PASS $LLSSHPASS_OPTS" + + $sshpasscmd ssh $LLSSH_OPTS $peer "$@" +} + +llscp_expand() +{ + local orig="$1" + local old_ifs="$IFS" + + local peer= + + IFS=: + set $@ + IFS="$old_ifs" + case $# in + 1) + echo "$1" + ;; + 2) + peer="$(llssh_expand $1 scp)" + [ "$peer" ] || return 1 + + echo "$peer:$2" + ;; + *) + echo "Error: Invalid location \"$orig1\"" >&2 + return 1 + ;; + esac +} + +# Usage: llscp +# +# scp(1) from to , but expand any host specified in either +# or , which matches an existing interface name, to a +# neighboring host on that interface. +llscp() +{ + local src="$(llscp_expand $1)" + local dst="$(llscp_expand $2)" + [ "$src" -a "$dst" ] || return 1 + shift 2 + + local sshpasscmd= + [ "$LLSSH_PASS" ] && sshpasscmd="sshpass -p$LLSSH_PASS $LLSSHPASS_OPTS" + + $sshpasscmd scp $LLSCP_OPTS "$src" "$dst" +}