Skip to content

Instantly share code, notes, and snippets.

@wallentx
Created July 28, 2025 18:36
Show Gist options
  • Save wallentx/2ac2b2f4c1b420db092ae697a9c8fad0 to your computer and use it in GitHub Desktop.
Save wallentx/2ac2b2f4c1b420db092ae697a9c8fad0 to your computer and use it in GitHub Desktop.
dumber than dumbpipe
#!/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