From 015a2942a281f79243db7e4a2134d73d67319a3c Mon Sep 17 00:00:00 2001 From: "kebler.net" Date: Sun, 20 Feb 2022 13:50:19 -0800 Subject: [PATCH] new repo with only common network script/modules. See archived repo for older commits --- alias/network | 7 ++ alias/networkd | 12 ++ env/backup.env | 2 + env/ssh-agent-socket.env | 2 + modules/net-utils.mod | 45 +++++++ modules/rrsync.sh | 246 +++++++++++++++++++++++++++++++++++++++ modules/ssh-copy.sh | 43 +++++++ modules/ssh.sh | 138 ++++++++++++++++++++++ modules/sshfs.sh | 92 +++++++++++++++ ssh/.gitignore | 1 + ssh/config/readme.md | 3 + ssh/session/interactive | 3 + ssh/session/readme.md | 1 + startup/ssh-agent-socket | 2 + 14 files changed, 597 insertions(+) create mode 100644 alias/network create mode 100644 alias/networkd create mode 100755 env/backup.env create mode 100644 env/ssh-agent-socket.env create mode 100644 modules/net-utils.mod create mode 100755 modules/rrsync.sh create mode 100644 modules/ssh-copy.sh create mode 100644 modules/ssh.sh create mode 100755 modules/sshfs.sh create mode 100644 ssh/.gitignore create mode 100644 ssh/config/readme.md create mode 100644 ssh/session/interactive create mode 100644 ssh/session/readme.md create mode 100644 startup/ssh-agent-socket diff --git a/alias/network b/alias/network new file mode 100644 index 0000000..1fd9b42 --- /dev/null +++ b/alias/network @@ -0,0 +1,7 @@ +alias ports="netstat -tulpn" +alias flushdns="systemctl restart systemd-resolved" + +alias nid="sudo ip link set down" +alias niu="sudo ip link set up" +alias nir1="nid eth1 && niu eth1 && nwr" +alias nir1="nid eth1 && niu eth1 && nwr" diff --git a/alias/networkd b/alias/networkd new file mode 100644 index 0000000..e05bbf6 --- /dev/null +++ b/alias/networkd @@ -0,0 +1,12 @@ +alias nws="sudo systemctl start systemd-networkd" +alias nwe="sudo systemctl enable systemd-networkd" +alias nwd="sudo systemctl disable systemd-networkd" +alias nwstp="sudo systemctl stop systemd-networkd" +alias nwr="sudo systemctl restart systemd-networkd" +alias nwdst="systemctl status systemd-networkd" +alias nwj="journalctl -u systemd-networkd" +alias nw="networkctl" +alias nwst="networkctl status" +alias nwl="networkctl lldp" + + diff --git a/env/backup.env b/env/backup.env new file mode 100755 index 0000000..2563ee5 --- /dev/null +++ b/env/backup.env @@ -0,0 +1,2 @@ +# set this if you have all networks common backup server api +# export BACKUP_SERVER=https://backup.xxxx.net \ No newline at end of file diff --git a/env/ssh-agent-socket.env b/env/ssh-agent-socket.env new file mode 100644 index 0000000..f81d33d --- /dev/null +++ b/env/ssh-agent-socket.env @@ -0,0 +1,2 @@ +# set ssh agent socket for each session if it exists +export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket" diff --git a/modules/net-utils.mod b/modules/net-utils.mod new file mode 100644 index 0000000..0291eef --- /dev/null +++ b/modules/net-utils.mod @@ -0,0 +1,45 @@ +#!/bin/bash + +# usage: +# [[ $(host_reachable host.net) ]] && echo sure || echo nope +# or +# host_reachable &> /dev/null && echo sure || echo nope +# or +host_reachable () { +if [[ $(command -v nmap) ]] && [[ $2 ]]; then + [[ $(nmap $1 -PN -p $2 | grep open) ]] && echo yes && return 0 || return 1 +fi +if [[ $(command -v nc) ]] && [[ $2 ]]; then +[[ $(nc -w 2 $1 $2) ]] && echo yes && return 0 || return 1 +fi +if [[ $(command -v ping) ]]; then +ping -c1 -W1 $1 &> /dev/null && echo yes && return 0 || return 1 +fi +return 2 # return 2 to indicate no method was available +} + +valid_ip() +{ + local ip=$1 + local stat=1 + local res + + if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + OIFS=$IFS + IFS='.' + ip=($ip) + IFS=$OIFS + [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \ + && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]] + res=$([ $? == 0 ] && echo true || echo false) + else + res=false + fi + echo $res +} + +get_domain() { +local domain +domain=$(echo $1 | awk -F\. '{print $(NF-1) FS $NF}') +echo "$domain" +} diff --git a/modules/rrsync.sh b/modules/rrsync.sh new file mode 100755 index 0000000..9d352e0 --- /dev/null +++ b/modules/rrsync.sh @@ -0,0 +1,246 @@ +#!/usr/bin/perl +# Name: /usr/local/bin/rrsync (should also have a symlink in /usr/bin) +# Purpose: Restricts rsync to subdirectory declared in .ssh/authorized_keys +# Author: Joe Smith 30-Sep-2004 +# Modified by: Wayne Davison +# https://www.guyrutenberg.com/2014/01/14/restricting-ssh-access-to-rsync/ +# insert this before key in authorized keys, include -ro before access root to limit to read only +# command="/path/to/rrsync /root/of/access" ,no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding +use strict; + +use Socket; +use Cwd 'abs_path'; +use File::Glob ':glob'; + +# You may configure these values to your liking. See also the section +# of options if you want to disable any options that rsync accepts. +use constant RSYNC => '/usr/bin/rsync'; +use constant LOGFILE => 'rrsync.log'; + +my $Usage = < 0, + 'backup-dir' => 2, + 'block-size' => 1, + 'bwlimit' => 1, + 'checksum-seed' => 1, + 'compare-dest' => 2, + 'compress-level' => 1, + 'copy-dest' => 2, + 'copy-unsafe-links' => 0, + 'daemon' => -1, + 'debug' => 1, + 'delay-updates' => 0, + 'delete' => 0, + 'delete-after' => 0, + 'delete-before' => 0, + 'delete-delay' => 0, + 'delete-during' => 0, + 'delete-excluded' => 0, + 'delete-missing-args' => 0, + 'existing' => 0, + 'fake-super' => 0, + 'files-from' => 3, + 'force' => 0, + 'from0' => 0, + 'fuzzy' => 0, + 'group' => 0, + 'groupmap' => 1, + 'hard-links' => 0, + 'iconv' => 1, + 'ignore-errors' => 0, + 'ignore-existing' => 0, + 'ignore-missing-args' => 0, + 'ignore-times' => 0, + 'info' => 1, + 'inplace' => 0, + 'link-dest' => 2, + 'links' => 0, + 'list-only' => 0, + 'log-file' => 3, + 'log-format' => 1, + 'max-delete' => 1, + 'max-size' => 1, + 'min-size' => 1, + 'modify-window' => 1, + 'new-compress' => 0, + 'no-implied-dirs' => 0, + 'no-r' => 0, + 'no-relative' => 0, + 'no-specials' => 0, + 'numeric-ids' => 0, + 'one-file-system' => 0, + 'only-write-batch' => 1, + 'owner' => 0, + 'partial' => 0, + 'partial-dir' => 2, + 'perms' => 0, + 'preallocate' => 0, + 'recursive' => 0, + 'remove-sent-files' => $only eq 'r' ? -1 : 0, + 'remove-source-files' => $only eq 'r' ? -1 : 0, + 'safe-links' => 0, + 'sender' => 0, + 'server' => 0, + 'size-only' => 0, + 'skip-compress' => 1, + 'specials' => 0, + 'stats' => 0, + 'suffix' => 1, + 'super' => 0, + 'temp-dir' => 2, + 'timeout' => 1, + 'times' => 0, + 'use-qsort' => 0, + 'usermap' => 1, +); + +### END of options data produced by the cull_options script. ### + +if ($short_disabled ne '') { + $short_no_arg =~ s/[$short_disabled]//go; + $short_with_num =~ s/[$short_disabled]//go; +} +$short_no_arg = "[$short_no_arg]" if length($short_no_arg) > 1; +$short_with_num = "[$short_with_num]" if length($short_with_num) > 1; + +my $write_log = -f LOGFILE && open(LOG, '>>', LOGFILE); + +chdir($subdir) or die "$0: Unable to chdir to restricted dir: $!\n"; + +my(@opts, @args); +my $in_options = 1; +my $last_opt = ''; +my $check_type; +while ($command =~ /((?:[^\s\\]+|\\.[^\s\\]*)+)/g) { + $_ = $1; + if ($check_type) { + push(@opts, check_arg($last_opt, $_, $check_type)); + $check_type = 0; + } elsif ($in_options) { + push(@opts, $_); + if ($_ eq '.') { + $in_options = 0; + } else { + die "$0: invalid option: '-'\n" if $_ eq '-'; + next if /^-$short_no_arg*(e\d*\.\w*)?$/o || /^-$short_with_num\d+$/o; + + my($opt,$arg) = /^--([^=]+)(?:=(.*))?$/; + my $disabled; + if (defined $opt) { + my $ct = $long_opt{$opt}; + last unless defined $ct; + next if $ct == 0; + if ($ct > 0) { + if (!defined $arg) { + $check_type = $ct; + $last_opt = $opt; + next; + } + $arg = check_arg($opt, $arg, $ct); + $opts[-1] =~ s/=.*/=$arg/; + next; + } + $disabled = 1; + $opt = "--$opt"; + } elsif ($short_disabled ne '') { + $disabled = /^-$short_no_arg*([$short_disabled])/o; + $opt = "-$1"; + } + + last unless $disabled; # Generate generic failure + die "$0: option $opt has been disabled on this server.\n"; + } + } else { + if ($subdir ne '/') { + # Validate args to ensure they don't try to leave our restricted dir. + s{//+}{/}g; + s{^/}{}; + s{^$}{.}; + die "$0: do not use .. in any path!\n" if m{(^|/)\\?\.\\?\.(\\?/|$)}; + } + push(@args, bsd_glob($_, GLOB_LIMIT|GLOB_NOCHECK|GLOB_BRACE|GLOB_QUOTE)); + } +} +die "$0: invalid rsync-command syntax or options\n" if $in_options; + +@args = ( '.' ) if !@args; + +if ($write_log) { + my ($mm,$hh) = (localtime)[1,2]; + my $host = $ENV{SSH_CONNECTION} || 'unknown'; + $host =~ s/ .*//; # Keep only the client's IP addr + $host =~ s/^::ffff://; + $host = gethostbyaddr(inet_aton($host),AF_INET) || $host; + printf LOG "%02d:%02d %-13s [%s]\n", $hh, $mm, $host, "@opts @args"; + close LOG; +} + +# Note: This assumes that the rsync protocol will not be maliciously hijacked. +exec(RSYNC, @opts, @args) or die "exec(rsync @opts @args) failed: $? $!"; + +sub check_arg +{ + my($opt, $arg, $type) = @_; + $arg =~ s/\\(.)/$1/g; + if ($subdir ne '/' && ($type == 3 || ($type == 2 && !$am_sender))) { + $arg =~ s{//}{/}g; + die "Do not use .. in --$opt; anchor the path at the root of your restricted dir.\n" + if $arg =~ m{(^|/)\.\.(/|$)}; + $arg =~ s{^/}{$subdir/}; + } + $arg; +} diff --git a/modules/ssh-copy.sh b/modules/ssh-copy.sh new file mode 100644 index 0000000..129ae25 --- /dev/null +++ b/modules/ssh-copy.sh @@ -0,0 +1,43 @@ +#!/bin/bash + + SSH_PUB_KEYS=${SSH_PUB_KEYS:-$HOME/.ssh} + export SSH_PUB_KEYS + + sshcp () { + echo args: $@ +# todo add a use password only flag +# local opts="-o PreferredAuthentications=password -o PubkeyAuthentication=no" + local dir="" + echo options $opts + [[ $1 = "-u" ]] && user=$2 && shift 2 || user=ubuntu + local host=$1 + [[ ! $(host_reachable $host) ]] && echo host $host not reachable, aborting mount && return 1 + local src=${2:-$(pwd)} + echo source: $src + [[ -d $src ]] && dir="-r" + echo scp $opts $dir "$src" $user@$host:$3 + scp $opts $dir "$src" $user@$host:$3 + } + + sshcpid () { + local opts="-o PreferredAuthentications=password -o PubkeyAuthentication=no" + local PUB_KEY=${SSH_PUB_KEYS:-$HOME/.ssh}/$3.pub + [[ $1 = "-u" ]] && user=$2 && shift 2 || user=ubuntu + dr="-n" + [[ $4 = "yes" ]] && dr="" || echo add "yes" as last argment to invoke + ssh-copy-id $opts $dr -f -i $PUB_KEY $1@$2 + } + + + sshd_disable_pw () { + module_load config_edit + local cnf=$(declare -f confirm) + local cc=$(declare -f config_change) + declare -A settings + local settings=( ["PasswordAuthentication"]=no ["PubkeyAuthentication"]=yes ["ChallengeResponseAuthentication"]=no) + #file=/etc/ssh/sshd_config + file=test.config + for setting in ${!settings[@]}; do + sudo bash -c "$cnf;$cc;config_change $setting ${settings[${setting}]} $file" + done + } \ No newline at end of file diff --git a/modules/ssh.sh b/modules/ssh.sh new file mode 100644 index 0000000..c46a1af --- /dev/null +++ b/modules/ssh.sh @@ -0,0 +1,138 @@ +#!/bin/bash +# this will superceed the ssh binary in order to source all the config files +module_load file # loads find and build_file + +[[ ! $SSH_CONFIG ]] && export SSH_CONFIG="$BASH_SHELL_ANY_NETWORK/ssh/_config" + +function ssh_config() { + local CDIRS + local CDIR + local DIRS + local DIR + local PDIRS + + declare OPTION + declare OPTARG + declare OPTIND + while getopts 'd:' OPTION; do + # echo $OPTION $OPTARG + case "$OPTION" in + d) + PDIRS=$OPTARG + # echo option d: $DIRS + ;; + *) + echo unknown option $OPTION + ;; + esac + done + + shift $((OPTIND - 1)) + + [[ $PDIRS ]] && DIRS=($PDIRS) || DIRS=(${BASH_SHELL_DIRS} "$HOME/$BASH_SHELL_USER") + # echo DIRS "${DIRS[@]}" + # echo $SSH_CONFIG + CDIRS=() + j=0 + cnt=${#DIRS[@]} + for ((i = 0; i < cnt; i++)); do + # echo $i of $cnt + # looks in ssh/config subdirectory of each DIRS is not passed + DIR="${DIRS[i]}$([[ ! $PDIRS ]] && echo /ssh/config)" + # echo ----- trying $DIR + [ -d $DIR ] && CDIRS[j]=$DIR + j+=1 || echo no directory $DIR + done + # CDIRS=("${CDIRS[@]}") + # echo ${CDIRS[@]} + + local HEADER="############################################################## +# THIS FILE IS GENERATED BY function ssh_config. Do not edit # +# It is created by combination of ssh configuration files # +# which are listed in a comment line before each # +# It is used by the ssh function which then calls ssh binary # +##############################################################" + + debug ssh config file at: $SSH_CONFIG + mkdir -p "$(dirname "$SSH_CONFIG")" + echo -e "$HEADER" >$SSH_CONFIG + # build_file appends the given file to output file cleanly with checks + # append any system config + build_file "/etc/ssh/ssh_config" $SSH_CONFIG + # echo existing dirs ${CDIRS[@]} + # will append any .cfg file found in ssh/config subdir of any BASH_SHELL_DIRS, including home shell + for CDIR in "${CDIRS[@]}"; do + # FILES=$(find -n '*.cfg' -d 0 $CDIR) + for f in $(_find -n '*.cfg' -p 'archive off' -d 0 $CDIR); do + # echo "Processing $f"; + [[ $f ]] && build_file "$f" $SSH_CONFIG + done + done + # append any tradtional home config + build_file "$HOME/.ssh/config" $SSH_CONFIG +} + +ssh() { + if [[ $SSH_CONFIG ]]; then + [[ ! -f "$SSH_CONFIG" ]] && ssh_config "$SSH_CONFIG" + command ssh -F $SSH_CONFIG "$@" + else + command ssh "$@" + fi +} + +sshp() { + local opts="-o PreferredAuthentications=password -o PubkeyAuthentication=no" + if [[ $SSH_CONFIG ]]; then + [[ ! -f "$SSH_CONFIG" ]] && ssh_config "$SSH_CONFIG" + command ssh $opts -F $SSH_CONFIG "$@" + else + command ssh $opts "$@" + fi +} + + ssh_test() { + echo running non-interactive ssh test on $2 with user $1 + ssh $1@$2 "cat .bashrc" + # env | grep -E 'SHELL|BASH|SSH';type module_load;module_load helpers;adirname . + } + +function rrem() { + ssh -X -t "$@" +} + +ssh_script () { + + local SUDO="" + + declare OPTION + declare OPTARG + declare OPTIND + while getopts 'ps:' OPTION; do + # echo $OPTION $OPTARG + case "$OPTION" in + p) + PASS=true + # echo option password login only: $PASS + ;; + s) + SUDO="sudo" + # echo option s: $SUDO + ;; + *) + echo unknown option $OPTION + ;; + esac + done + + shift $((OPTIND - 1)) + + HOST=$1@$2 + SCRIPT=$3 + + # ssh < 'bash -s' << local_script.sh + + scp $PATHtoSCRIPT$SCRIPTname $HOSTtoCONTROL:/tmp/ + ssh -t $HOSTtoCONTROL "sudo -s bash /tmp/$SCRIPTname" + ssh root@MachineB 'bash -s' < local_script.sh +} diff --git a/modules/sshfs.sh b/modules/sshfs.sh new file mode 100755 index 0000000..1625b38 --- /dev/null +++ b/modules/sshfs.sh @@ -0,0 +1,92 @@ +#!/bin/bash +# depends on sshfs fuse for ssh +module_load filesystem # mounted +module_load net-utils # host_reachable +module_load ssh + +function smount() { + + local HOST + local PORT + local CONFIG=$SSH_CONFIG + local PORT=22 + + declare SSHOPTS + declare OPTION + declare OPTARG + declare OPTIND + declare MNTUSER + while getopts 'u:np:o:F:' OPTION; do + # echo $OPTION $OPTARG + case "$OPTION" in + p) + PORT=$OPTARG + # echo option d: $DIRS + ;; + u) + MNTUSER=$OPTARG + ;; + n) + MNTUSER=_NONE_ + ;; + o) + echo "adding sshfs option: $OPTARG" + SSHOPTS="$SSHOPTS -o $OPTARG" + ;; + F) + echo "using SSH Config file at: $OPTARG" + CONFIG=$OPTARG + ;; + + *) + echo unknown option $OPTION + ;; + esac + done + + shift $((OPTIND - 1)) + + # first item is nowsource, second is local mount point, third is possbile local user + HOST=$(sed 's/.*@\(.*\):.*/\1/' <<<"$1") + + [[ ! $(host_reachable $HOST $PORT) ]] && echo host $HOST not reachable, aborting mount && return 1 + if [[ $(mounted $2) ]]; then + echo "aborting mount: $1 already mounted at $2" + else + mkdir -p $2 + # can add any options after mount point directory like -o default_permissions + config=$([[ -f $CONFIG ]] && echo "-F $CONFIG") + if [[ ! $MNTUSER == "_NONE_" ]]; then + MNTUSER=${MNTUSER:-$USER} + id=$(id -u ${MNTUSER}) + if [[ $id ]]; then + SSHOPTS="$SSHOPTS -o uid=$id -o allow_other" + else + echo no user ${MNTUSER} on this machine, aborting mount + return 1 + fi + else + MNTUSER="" + fi + args="-p $PORT $SSHOPTS $config $1 $2" + echo SSHFS $([[ $MNTUSER ]] && echo mounted as user ${MNTUSER}): $args + sshfs $args + fi +} + +function usmount() { + if [[ $(mounted $1) ]]; then + echo "unmounting remote file system at $1" + fusermount -u $1 + else + echo "nothing mounted at $1, aborting unmount" + fi +} + +function mntBackup() { + smount root@$1:/backup /backup/remote -p 22 -o allow_other +} + +function umntBackup() { + usmount /backup/remote +} diff --git a/ssh/.gitignore b/ssh/.gitignore new file mode 100644 index 0000000..b3483f8 --- /dev/null +++ b/ssh/.gitignore @@ -0,0 +1 @@ +/_config diff --git a/ssh/config/readme.md b/ssh/config/readme.md new file mode 100644 index 0000000..689e50b --- /dev/null +++ b/ssh/config/readme.md @@ -0,0 +1,3 @@ + +all files in this ssh/config subdirectory will be incorporated into a master ssh configuration per the ssh_config function in the ssh module + diff --git a/ssh/session/interactive b/ssh/session/interactive new file mode 100644 index 0000000..fc790db --- /dev/null +++ b/ssh/session/interactive @@ -0,0 +1,3 @@ +if [[ $- == *i* ]]; then +echo ssh interactive session +fi diff --git a/ssh/session/readme.md b/ssh/session/readme.md new file mode 100644 index 0000000..223d2e1 --- /dev/null +++ b/ssh/session/readme.md @@ -0,0 +1 @@ +*anything in /session will be sourced if this is a remote ssh login session* diff --git a/startup/ssh-agent-socket b/startup/ssh-agent-socket new file mode 100644 index 0000000..a2c0a2a --- /dev/null +++ b/startup/ssh-agent-socket @@ -0,0 +1,2 @@ +export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket" +llog "ssh socket set to: $(env | grep SSH_AUTH_SOCK)"