Created
July 28, 2025 18:36
-
-
Save wallentx/2ac2b2f4c1b420db092ae697a9c8fad0 to your computer and use it in GitHub Desktop.
dumber than dumbpipe
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
set -euo pipefail | |
usage() { | |
cat <<EOF | |
Usage: | |
dumberpipe listen PORT | |
dumberpipe send [-s SRC_IP] REMOTE_HOST:PORT FILE | |
Options: | |
-s SRC_IP source IP/hostname for nc -s (send mode only) | |
EOF | |
exit 1 | |
} | |
# at least mode | |
(($# >= 1)) || usage | |
mode="$1" | |
shift | |
# defaults | |
src_ip="" | |
port="" | |
# manual parse of -s (only for send mode) | |
while [[ $# -gt 0 ]]; do | |
case "$1" in | |
-s) | |
[[ $# -lt 2 ]] && { | |
echo "β Missing argument for -s" >&2 | |
usage | |
} | |
src_ip="$2" | |
shift 2 | |
;; | |
--) | |
shift | |
break | |
;; | |
-*) | |
echo "β Unknown option: $1" >&2 | |
usage | |
;; | |
*) break ;; | |
esac | |
done | |
# assemble the nc -s flag if needed (only for send mode) | |
nc_src=() | |
[[ -n $src_ip ]] && nc_src=(-s "$src_ip") | |
# helper to get file size | |
get_size() { | |
local f=$1 | |
if stat --version &>/dev/null; then | |
stat -c%s "$f" | |
else | |
stat -f%z "$f" | |
fi | |
} | |
case "$mode" in | |
listen) | |
(($# == 1)) || usage | |
port="$1" | |
[[ "$port" =~ ^[0-9]+$ ]] || { | |
echo "β Invalid port: $port. Must be a number." >&2 | |
usage | |
} | |
echo -e "π Waiting for transfer on TCP port '$port'β¦" | |
coproc NC { nc -l -p "$port"; } | |
exec {R}<&"${NC[0]}" # socket read | |
exec {W}>&"${NC[1]}" # socket write | |
# Phase 1: read headers | |
declare -A hdr | |
while IFS= read -r -u $R line; do | |
[[ -z $line ]] && break | |
k=${line%%:*} | |
v=${line#*:} | |
hdr[$k]="$v" | |
done | |
fname="${hdr[FILENAME]}" | |
fsize="${hdr[FILESIZE]}" | |
finfo="${hdr[FILEINFO]}" | |
echo "π₯ Incoming: '$fname' (${fsize} bytes)" | |
echo "π Type: $finfo" | |
read -rp "Save as [${fname}]: " out </dev/tty | |
out=${out:-$fname} | |
[[ -d $out ]] && out="${out%/}/$fname" | |
read -rp "Accept transfer? [y/N]: " ans </dev/tty | |
if [[ $ans =~ ^[Yy]$ ]]; then | |
printf "OK\n" >&$W | |
# Start file transfer in background | |
cat <&$R > "$out" & | |
cat_pid=$! | |
# Monitor file size and kill when complete | |
while kill -0 $cat_pid 2>/dev/null; do | |
if [[ -f "$out" ]]; then | |
current_size=$(stat -f%z "$out" 2>/dev/null || stat -c%s "$out" 2>/dev/null || echo 0) | |
if [[ $current_size -ge $fsize ]]; then | |
break | |
fi | |
fi | |
sleep 0.1 | |
done | |
# Kill the background process | |
kill $cat_pid 2>/dev/null || true | |
echo "β Saved to $out" | |
else | |
printf "NO\n" >&$W | |
# Drain the connection in background | |
cat <&$R > /dev/null & | |
cat_pid=$! | |
# Wait a bit then kill | |
sleep 2 | |
kill $cat_pid 2>/dev/null || true | |
echo "β Transfer rejected" | |
fi | |
# Close file descriptors and exit | |
exec {R}<&- | |
exec {W}>&- | |
kill $NC_PID 2>/dev/null || true | |
;; | |
send) | |
(($# == 2)) || usage | |
remote_host_port="$1" | |
infile="$2" | |
# Parse REMOTE_HOST:PORT | |
if [[ "$remote_host_port" =~ ^([^:]+):([0-9]+)$ ]]; then | |
remote_host="${BASH_REMATCH[1]}" | |
port="${BASH_REMATCH[2]}" | |
else | |
echo "β Invalid format: $remote_host_port. Expected HOST:PORT" >&2 | |
usage | |
fi | |
[[ -f $infile ]] || { | |
echo "β File not found: $infile" >&2 | |
exit 1 | |
} | |
fname=$(basename "$infile") | |
fsize=$(get_size "$infile") | |
finfo=$(file -b "$infile") | |
echo "π Connecting to '$remote_host':'$port'β¦" | |
coproc NC { nc "${nc_src[@]}" "$remote_host" "$port"; } | |
exec {R}<&"${NC[0]}" | |
exec {W}>&"${NC[1]}" | |
echo "β Connection established!" | |
echo "β Waiting for receiver to acceptβ¦" | |
printf "FILENAME:%s\nFILESIZE:%s\nFILEINFO:%s\n\n" \ | |
"$fname" "$fsize" "$finfo" >&$W | |
if read -r -u $R resp && [[ $resp == OK ]]; then | |
echo "βΆοΈ Sending '$fname'β¦" | |
cat "$infile" >&$W | |
echo "β Sent '$fname' (${fsize} bytes) to $remote_host:$port" | |
else | |
echo "β Rejected by receiver" | |
fi | |
# Close file descriptors and exit | |
exec {R}<&- | |
exec {W}>&- | |
kill $NC_PID 2>/dev/null || true | |
;; | |
*) | |
usage | |
;; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment