Pure Bash Web Server
github.com
github.com
#!/bin/bash
cd songs
if [[ ! -p q ]]; then
mkfifo q
fi
(while true; do echo "playing" | nc -l 10000 | head -n 1 | cut -f 2 -d " " | cut -b 2- | grep -E "^[a-zA-Z0-9/:.?=-]{1,}$" > q; done) &
while true; do
if read a <q; then
echo $a;
fn=$(youtube-dl -f m4a --id --get-filename $a);
youtube-dl -f m4a --id $a
echo $fn
mplayer $fn
fi
done
To queue up a song, we'd find it on youtube and prepend "http://jukebox.local:10000/" to the urlThe post is about doing all of this in pure bash builtins like /dev/tcp and bash functions. Not about gluing together tools which do the work.
> A purely bash web server, no socat, netcat, etc...
It's like replying to a thread about implementing a web server in C macros with how you implemented a music jukebox as a standard C program. Great, but also not the point or really even related.
Debug containers are now a stable feature in Kubernetes. It honestly boggles my mind how companies will throw so much time, money, and effort into the cybersecurity product du jour when they can get the vast majority of the value by moving everything into distroless, shell-less containers running on managed VMs that are optimized for container workloads.
E.g., if you just sort of roll with the defaults, you're dropped into a pod in a very confused state: `ps -ef` says nothing in your debugee is running, and the filesystem of the debugee is nowhere to be found.
You can work around both of those (the first is --target, but the latter requires an intricate SO answer¹) but its the sort of thing that would be nicer out of the box?
The node debugging mode is a bit better: by default, puts you in at least the host pidns, and mounts the host FS.
¹https://stackoverflow.com/questions/73355970/how-to-get-acce...
I would agree, but so much of day-to-day Kubernetes is arcane CLI commands to begin with. Other stuff that is non-trivial to do on the CLI but comes up in most reasonable production deployments:
* Rotating secrets without exposing the secret to the shell history file (hint: kubectl apply -f can take - to signify atdin, but not kubectl patch!)
* Ensuring your edits to a ConfigMap pass application-level validation (i.e. your configuration changes won't crash your app, not just that it's a valid ConfigMap)
* Anything to do with user auth or RBAC
* Scaling the default persistent volume size of a StatefulSet
The truth is that Kubernetes is a platform, and just like how most people don't want to run a bare copy of Bash or VIM on their laptop, people will figure out aliases, one-liners, and other functions to help make them effective. So some of working effectively with Kubernetes means, yes, building your own custom debug containers, and writing your own helper shell stuff.Any command in shell with a space before it will be omitted from history.
Agree it should take input from stdin.
Always check your shell before assuming this will work!
For applications that aren't super high security, I've been really appreciating using immutable hosts (that get regularly updated/rotated), along with CI/CD that is constantly rebuilding from source, applying latest software updates, and deploying the latest version of the app. Combined with other tools like scanners, and de-bloating your images, it really raises the height of the fruit.
Seems only marginally better than using nsenter on a privileged container to just go muck with the host
A lot of the CDNs even use tools like kubevirt where the segmentation is even further. And then we have gvisor, firecracker, etc.
I admittedly haven't touched k8s code since 1.18 but I can't think of anything like you're referring to and I definitely would like to know about it.
Thanks.
https://github.com/torvalds/linux/blob/master/fs/Kconfig.bin...
config BINFMT_SCRIPT
tristate "Kernel support for scripts starting with #!"
default y
help
Say Y here if you want to execute interpreted scripts starting with
#! followed by the path to an interpreter.No personal attack intended, I am wondering this about my own embedded product which contains Python.
I'm really happy to see somebody shared it on hackernews :D If you have some questions, feel free to ask me
You could avoid loadables.
Finfo <- load file inside a variable and get the size Mktemp <- like you said with timestamp Rm <- with a fifo or variable
The thing is, shell can't cope with nulls -- if you do something like
n=$(gzip -9 < /etc/passwd)
gzip -9 < /etc/passwd | sum
echo "$n" | sum
This falls apart because shell just can't deal with nulls.You can probably hack around all those issues, and may not run into this too much, at first, in a web server, but golly you'll pretty quickly fall into a pit.
tr -dc '[[:print:]]'
Will sanitize strings of non-printable characters. While it is true that you can't have nulls inside bash variables, your example actually contains the correct syntax if you just remove the first and last lines.But -- importantly -- running
n=$(gzip -9 < /etc/passwd | tr -dc '[[:print:]]')
may process the nulls, but is it reversible? Can I now send $n into gzip -d and get whatever I put into it out?I can do things that are reversible --
n=$(gzip -9 < /etc/passwd | base64 )
But now I can't process the output "natively" except by calling base64 every time.And maybe I've gotten myself into this hole because sometimes the contents of $n have nulls and other times not?
Pure shell is a road to madness. Don't ask me how I know...
I mentioned the sanitization in the context of taking user input (since we are talking about a bash web server) because I thought you were pointing out a user could do bad things by feeding in nulls.
As glue, shell's wonderful. Reading from /dev/tcp/ and such is a cute trick but ultimately a dead dead dead end.
Before I really knew how to program I was a systems administrator and used nothing but bash via CGI to build a $2k/month revenue site, so obviously your claims of it being a dead end are just hyperbole.
I'm proud of you for making a ton of money on bash using CGI; "it's not dumb if it works" but ... doing complex stuff like this in shell is ... dumb.
At least, I certainly know better. You do you, though.
It's not dumb if you know what you are doing. I and others have pointed out how to properly handle binary data in shell scripts.
This might be a good start if you'd like to learn more: https://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html
That How-to doesn't mention that shell eats nulls. If you're using shell as glue, that doesn't matter, but if you're using shell to process (not pass to another program) raw tcp connections, you'll need to manage binary data, which is full of nulls.
Perhaps you're not even aware of these issues? Anyhow, go on about your life grand troll, you're the winner.
gzip -9 < /dev/random | dd of=/tmp/gibberish
the shell's not actually doing anything but forking things and connecting file descriptors of processes to each other gzip -9 < /dev/random | while read line ; do echo "$line" ; done > /tmp/gibberish
The stdout of gzip is being processed by shell, and will make all the nulls go away.(edited to add another example:)
Similarly - it isn't printing that you can't do -- it's anything -- consider:
case $(cat /bin/sh)
in
$(cat /bin/bash)) echo "they're the same!" ;;
*) echo "they're not the same!" ;;
esac
This is obviously an insane way to see if two files are identical, but worse -- it's going to fail for two different files whose only difference is how many nulls are in the file.Show HN: A pure bash web server. No netcat, socat, etc. - https://news.ycombinator.com/item?id=29794979 - Jan 2022 (97 comments)
https://www.amazon.com.br/Script-Profissional-Aurelio-Marinh...
tee /tmp/server > /dev/null <<'EOF'
#!/bin/bash
set -euo pipefail
SERVE="$1"
TYPE="$2"
read -a WORDS
if [ "${#WORDS[@]}" != 3 ] || [ "${WORDS[0]}" != "GET" ]; then
echo -ne "HTTP/1.1 400 Bad request\r\n\r\n"; exit 0
fi
# Subfolders are not supported for security reasons as this avoids having to deal with ../../ attacks
FILE="${SERVE}/$(basename -- "${WORDS[1]}")"
if [ -d "${FILE}" ] || [ ! -e "${FILE}" ]; then
echo -ne "HTTP/1.1 404 Not found\r\n\r\n" ; exit 0
fi
echo -ne "HTTP/1.1 200 OK\r\n"
echo -ne "Content-Type: ${TYPE};\r\n"
LEN=$(stat -L --printf='%s\n' "${FILE}")
echo -ne "Content-Length: ${LEN}\r\n"
echo -ne "\r\n"
cat "${FILE}"
EOF
chmod +x /tmp/server
# switch from "text/plain" to "application/octet-stream" for file downloads
socat TCP-LISTEN:8000,reuseaddr,fork SYSTEM:'/tmp/server /tmp/ text-plain'
# test:
curl -v http://localhost:8000/server A purely bash web server, no socat, netcat, etc...cool project
I feel lied to and I want a refund.