这是在默认包管理器之外的网络上查找侦听过程的后续问题
由于使用了/proc,我设法使它变得更快一些,并希望能够实现大多数建议。一些小问题
readarray函数吗?它占用了太多的空间,只使用过一次。一直在努力寻找一个简洁的替代品。和以前一样,它的工作原理与预期一样。
Improved代码
#!/bin/bash
# finds processes listening in on the network outside outside of the default package manager
usage=$(cat <<-EOF
$(basename "$0").sh [-h] [-f] [-a] [-w] [-v] [-p]
Lists packages listening on the network outside of the default package manager
where:
-h, --help show this help text
-f, --whitelist-file pick a file[s] containing whitelisted programs
-w, --whitelist explicitly add whitelisted programs
-W, --ignore-whitelist ignore the whitelist, includes env variables
-v, --view-whitelist view the complete whitelist
-p, --package-manager which package-manager to use (rpm, dkpg, ...)
-P, --ignore-package-manager ignores the check for a working package manager
output:
COMMAND PATH PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mattermos /app/main/mattermo 3351 361000 25u IPv4 84625698 0t0 TCP 129.240...(ESTABLISHED)
examples:
List all processes listening on the network
usit_network_network_listening_processes --list-all
List only packages not maintained by the central package manager system
usit_network_network_listening_processes --list-all
Whitelist some processes
usit_network_network_listening_processes --whitelist mattermos,systemd
usit_network_network_listening_processes --whitelist 'mattermos systemd'
Whitelist some processes using whitelist files
usit_network_network_listening_processes -f /etc/uio/uio_network_listening_processes_whitelist_01.txt
Multiple whitelist files is supported
usit_network_network_listening_processes --whitelist foo.txt,bar.txt
environment variables:
The following environment variables are available
USIT_LISTENER_WHITELIST
USIT_LISTENER_WHITELIST_FILES
These form the base for the whitelist and whitelist files respectively.
Use a string with spaces or comma [,] as seperator for the values.
EOF
)
fatal() {
printf "ERROR: $*" >&2
exit 1
}
# This is a substitute for readarray for older bash versions
# https://stackoverflow.com/a/64793921/1048781
if ! type -t readarray >/dev/null; then
# Very minimal readarray implementation using read. Does NOT work with lines that contain double-quotes due to eval()
readarray() {
local cmd opt t v=MAPFILE
while [ -n "$1" ]; do
case "$1" in
-h|--help) echo "minimal substitute readarray for older bash"; exit; ;;
-r) shift; opt="$opt -r"; ;;
-t) shift; t=1; ;;
-u)
shift;
if [ -n "$1" ]; then
opt="$opt -u $1";
shift
fi
;;
*)
if [[ "$1" =~ ^[A-Za-z_]+$ ]]; then
v="$1"
shift
else
echo -en "${C_BOLD}${C_RED}Error: ${C_RESET}Unknown option: '$1'\n" 1>&2
exit
fi
;;
esac
done
cmd="read $opt"
eval "$v=()"
while IFS= eval "$cmd line"; do
line=$(echo "$line" | sed -e "s#\([\"\`]\)#\\\\\1#g" )
eval "${v}+=(\"$line\")"
done
}
fi
# Transform long options to short ones
args=()
for arg; do
case $arg in
'--whitelist') args+=(-w) ;;
'--whitelist-file') args+=(-f) ;;
'--ignore-whitelist') args+=(-W) ;;
'--ignore-package-manager') args+=(-P) ;;
'--view-whitelist') args+=(-v) ;;
'--package-manager') args+=(-p) ;;
'--help') args+=(-h) ;;
*) args+=("$arg") ;;
esac
done
set -- "${args[@]}"
# The '//,/ ' allows us to input variables using , seperator as well as SPACE
whitelist=()
whitelist_files=()
read -ar whitelist <<< "${USIT_LISTENER_WHITELIST//,/ }"
read -ar whitelist_files <<< "${USIT_LISTENER_WHITELIST_FILES//,/ }"
view_whitelist=false
ignore_whitelist=false
ignore_package_manager=false
while getopts ":w:f:p:vPWh" flag; do
case "${flag}" in
h)
echo "$usage"
exit 0
;;
v) view_whitelist=true ;;
W) ignore_whitelist=true ;;
P) ignore_package_manager=true ;;
w) read -ra parts <<< "${OPTARG//,/ }"
whitelist+=("${parts[@]}")
;;
f) read -ra parts <<< "${OPTARG//,/ }"
whitelist_files+=("${parts[@]}")
;;
p) package_manager=${OPTARG} ;;
\?)
fatal "illegal option: -%s${OPTARG} \n\n$usage\n\n"
;;
esac
done
# -i : This option filters only processes whith an IPv[46] address:
# -P : This option inhibits the conversion of port numbers to port names for network files.
# -n : This option inhibits the conversion of network numbers to host names for network files.
# -l : This option inhibits the conversion of user ID numbers to login names.
# +M : Enables the reporting of portmapper registrations for local TCP and UDP ports.
# The awk filters only unique PID's by _[val] looks up val in the hash _(a regular variable).
# NR > 1 is used to skip the header
network_listening_processes=$(
lsof -Pnl +M -i |
awk 'NR>1 && !seen[$1]++ { print }'
)
# we use the realpath -m to extract the execution path from the process id (pid)
network_listening_processes_with_path=$(
while read -r a pid b; do
printf "%s %s %s %s\n" "$a" "'$(realpath -m /proc/"$pid"/exe)'" "$pid" "$b"
done <<< "${network_listening_processes[@]}"
)
if "${ignore_whitelist}" && "${ignore_package_manager}"; then
echo "${network_listening_processes_with_path}" | column -t
exit
fi
function is_in_array {
local array="$1[@]"
local seeking="${!2}"
local result=1
for element in "${!array}"; do
if [[ $element == "$seeking" ]]; then
result=0
break
fi
done
return $result
}
function is_empty_array {
local array="$1[@]"
for element in "${!array}"; do
return 1
done
return 0
}
function print_array {
local array="$1[@]"
for element in "${!array}"; do
echo "${element}"
done
}
# Block of code for getting the correct package manager
is_in_standard_repo_rpm() {
rpm -qf "${1}" &>/dev/null
}
is_in_standard_repo_dpkg() {
dpkg -S "${1}" &>/dev/null
}
is_in_standard_repo_any() {
local package="${1}"
return 1
}
if "${ignore_package_manager}"; then
package_manager="any"
else
dpkg_equivalents=("dpkg" "apt" "")
rpm_equivalents=("rpm" "yum" "dnf" "")
if is_in_array dpkg_equivalents package_manager && dpkg --version &>/dev/null; then
package_manager="dpkg"
elif is_in_array rpm_equivalents package_manager && rpm --version &>/dev/null; then
package_manager="rpm"
else
fatal "No supported package manager found! Try specifying one with -p --package-manager"
fi
fi
is_in_standard_repo () {
is_in_standard_repo_$package_manager "${!1}"
}
# block of code for handling the whitelist
if "${ignore_whitelist}"; then
whitelist=()
else
if ! is_empty_array whitelist_files; then
readarray -t whitelist_from_file < <(sort -u "${whitelist_files[@]}")
whitelist+=("${whitelist_from_file[@]}")
fi
fi
if "${view_whitelist}"; then
! is_empty_array whitelist && print_array whitelist
exit
fi
# Finally we list every process not in the default packagen_manager
# Which is listening on the network
while IFS= read -r line; do
programname=$(awk '{print $1}' <<< "${line}")
path=$(awk '{print $2}' <<< "${line}")
path_without_quotes=$(sed 's/^.\(.*\).$/\1/' <<< "${path}")
if ! is_in_standard_repo path_without_quotes && ! is_in_array whitelist programname; then
echo "${line}"
fi
done <<< "${network_listening_processes_with_path}" | column -t发布于 2022-08-28 16:25:03
https://codereview.stackexchange.com/questions/279233
复制相似问题