-
Notifications
You must be signed in to change notification settings - Fork 0
/
bnc
executable file
·91 lines (77 loc) · 2.59 KB
/
bnc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/bin/bash -e
# An IRC bouncer (BNC) in Bash.
relay() {
declare in="$1" out="$2" logfile="$3" host="$4" port="${5:-6667}"
echo "Connecting to IRC server on ${host}:${port}."
nc "$host" "$port" < "$in" | logger "[relay] " "$logfile" > "$out"
echo "Lost connection to IRC server."
}
client() {
declare in="$1" out="$2" logfile="$3" host="${4:-localhost}" port="${5:-16667}"
echo "Listening for IRC clients on ${host}:${port}."
while [ 1 ]; do
nc -l "$host" "$port" < "$in"
# Replay log.
# TODO: Replay only the parts we actually need?
cat "$logfile" > "$in" &
done | client_middleware | logger "[client]" > "$out"
}
client_middleware() {
# Consume messages we don't want to relay.
local connected=0
while read line; do
# Parse commands, look like this: "COMMAND args..."
case "$line" in
QUIT*)
# Discard QUIT messages, because we're not quitters.
continue
;;
NICK* | USER* | PASS*)
if [[ $connected -ge 2 ]]; then
# Skip logging in again.
echo "Skipping welcome: $line" > /dev/stderr
continue
fi
((connected=connected+1))
echo "$line"
;;
*)
echo "$line"
esac
done
}
logger() {
# Helper for debugging (output to stderr) and replay (logfile)
declare prefix="$1" logfile="$2"
while read line; do
echo "${prefix} ${line}" > /dev/stderr
if [[ "$logfile" ]]; then
echo "${line}" >> "$logfile"
fi
echo "${line}"
done
}
##
usage() {
echo "Single-user IRC bouncer (BNC) for a given IRC_HOST server."
echo "Usage: ${0} IRC_HOST [IRC_PORT [BNC_HOST [BNC_PORT]]]"
}
main() {
set -eo pipefail; [[ "$TRACE" ]] && set -x
declare host="$1" port="${2:-6667}" bnchost="${3:-localhost}" bncport="${4:-16667}"
if [[ ! "${host}" ]] || [[ "${host:0:1}" == "-" ]]; then
usage
exit 1
fi
# Setup temporary workdir for our fifos.
readonly workdir="$(mktemp -d -t $(basename $0))"
# Cleanup
trap 'rm -rf "$workdir"' EXIT
trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT
mkfifo "$workdir/in" "$workdir/out"
client "$workdir/in" "$workdir/out" "$workdir/irc.log" "$bnchost" "$bncport" &
relay "$workdir/out" "$workdir/in" "$workdir/irc.log" "$host" "$port"
# TODO: Make sure client loop dies with the relay
# TODO: Defer opening relay until first client connected?
}
main $@