Bash Socket Programming

There is a little known feature of Bash that allows a programmer to send and receive data from a device socket that you can create in Bash. This is especially handy if you have a service running on your system that is listening for data on a port, and a shell script that handles another function, you can communicate between your shell script and your service via the local loopback bound with this socket. Another trick allows you to send a GET request from this Bash socket to a website much like wget does and retrieve the HTML code of that page using Bash redirection.

Create Socket In Bash

To create a socket in Bash we take advantage of the Bash exec command, and redirection. To open a bidirectional udp socket to a specific IP address and specific port we use the /dev/udp/ip/port syntax. So for example, if we wanted to send to the loopback device on port 12345, we use /dev/udp/127.0.0.1/12345 as our device. We then use exec and redirection on this path to create the socket. We use file handles 3 or higher, as mentioned in the earlier redirection article, stdin = 0 and stdout = 1 and stderr = 2 and thus we have to use 3 or higher. Putting it all together:

exec 3<> /dev/udp/127.0.0.1/12345

We can now direct data to the 3 file handle much like directing data to /dev/null or standard out. Lets verify that the socket was made using netstat.

$ netstat -u
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
udp        0      0 localhost:40834         localhost:12345         ESTABLISHED

Okay, we definitely have a socket open, lets send data to it.

echo "hi" >&3

This will send the string “hi” to the local loopback at port 12345, so if you had a C service listening for the string, it could act upon the receipt of that traffic. Lets watch this in action. I have a tcpdump session running in another terminal to grab the data being sent.

# tcpdump -i lo -n -vv -s 256 -X
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 256 bytes
15:21:13.613402 IP (tos 0x0, ttl 64, id 64305, offset 0, flags [DF], proto UDP (17), length 31)
    127.0.0.1.40834 > 127.0.0.1.12345: [bad udp cksum 91c1!] UDP, length 3
        0x0000:  4500 001f fb31 4000 4011 419a 7f00 0001  E....1@.@.A.....
        0x0010:  7f00 0001 9f82 3039 000b fe1e 6869 0a    ......09....hi.

Well look at that! At the very end of line 6, you can see the “hi” being sent to 127.0.0.1 at port 12345.

Nifty! To create a tcp socket you simply replace the /udp/ with the /tcp/ and voila, TCP socket made. Of course if you plan to use TCP then you have to take into account the handshake procedure and listening for the returned data.

Close Socket File Handle

To close the file handle after use execute the commands:

exec 3<&-
exec 3>&-

This is important to do, as leaving this handle open has potential as a method of attack on the system.

Send Get Request To Google With Bash Socket

Another cool trick using the Bash socket is to create your socket for a website rather than strictly an IP address. In doing so, we can send a GET request to the web server and wait for a reply back. The commands to achieve this are:

$ exec 3<>/dev/tcp/www.google.com/80
$ echo -e "GET / HTTP/1.1\n\n" >&3
$ cat <&3
HTTP/1.1 302 Found
Location: http://www.google.ca/
Cache-Control: private
Content-Type: text/html; charset=UTF-8
Set-Cookie: PREF=ID=c0937b14e3b5e4a2:FF=0:TM=1304375672:LM=1304375672:S=qvrh_IjuRcStbI-i; expires=Wed, 01-May-2013 22:34:32 GMT; path=/; domain=.google.com
Date: Mon, 02 May 2011 22:34:32 GMT
Server: gws
Content-Length: 218
X-XSS-Protection: 1; mode=block
 
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.ca/">here</A>.
</BODY></HTML>

Sweet! I found that nifty example here. With some other great comments from other users.

There you have it, there are many uses for Bash sockets when your system may not have netcat.

Bash Redirection Of stderr And stdout

If you are running the BASH shell on your Linux or Unix system then you can utilize these redirection examples. There are many ways to redirect input and output from the bash shell environment. This article will outline how to redirect stderr, redirect stdout and how to redirect stderr to stdout.

In BASH, 1 represents stdout or (standard output) and 2 represents stderr or (standard error). This is useful from a C binary when using fprintf to send error data to a specific file and normal output data to another.

1. Standard Output (stdout) To A File

This is the most common usage of Bash redirection:

$ cat data.txt > new_file.txt

All standard output from our cat’ing of the file will end up in new_file.txt.

2. Redirect Standard Error (stderr) To A File

To redirect stderror to a file we must use the numeric definition of standard error.

$ cat data.txt 2> output_error.txt

This will populate the file with standard error material.

3. Send Standard Out (stdout) And Standard Error (stderr) To A File

To send both standard out and standard error to a file we can use &> for redirection.

$ cat data.txt &> all_output.txt

4. Standard Error (stderr) To Standard Out (stdout)

It is sometimes useful to store both standard output and and standard error in the same place, but sending it through standard out. Using 2>&1

$ cat data.txt 2>&1 output.txt

5. Redirect All Output To The Bit Bucket In The Sky

To redirect all output to a sink hole, we can redirect to /dev/null.

$ cat data.txt &> /dev/null

In my examples I used cat, but you could use any program or shell script that outputs data. All redirection is processes by the BASH shell.

Create Aliases in Bash Shell

Most programmers always want to figure out a more efficient or easier way of doing something to save us time and effort. An alias in bash is meant for just that. An alias is essentially a keyboard shortcut or replacement mechanism for commonly typed commands in your shell. You are able to set them temporarily or permanently if placed in the correct file.

I will show you how to display current aliases already on your system, yes there are a few built-ins! I will also show you how to make your own and have them on your system during boot-up.

Show All Current Bash Aliases With ‘alias -p’

To display all the current aliases on your system as a normal user, type alias -p.

$ alias -p
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias ls='ls --color=auto'

And how! So how do these work? For instance, every time I type the ‘ls’ command the bash shell secretly replaces my ‘ls’ entry with ‘ls –color=auto’ so when I type ‘ls’ I get the pretty listing of my files all nicely colored. Awesome. So for us lazy people this can become quite handy! One command I type quite often is ‘ps aux wwwf’ to display all my processes current usage, thread output, etcetera. But that is a lot to type. So lets make an alias to save me time. I will call my alias ‘p’.

$ alias p="ps aux wwwf"
$ alias 
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias ls='ls --color=auto'
alias p='ps aux wwwf'

Now you can see I have my process output alias. This is great, because anytime I need to check my systems process output I can just type ‘p’ instead of that lengthy spiel.

The lifetime of my new alias is only as long as the lifetime of my current shell. So when I exit the shell, the alias goes with it. If we want our alias to persist it must be stored in /etc/profile, .bash_aliases or your .bashrc file in your home directory.

Store Alias In File For Longevity

To create persistent aliases you must place them in one of three files:

  • /etc/profile
  • .bashrc
  • .bash_aliases

For example, an excerpt from my .bashrc file:

# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
    test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
    alias ls='ls --color=auto'
    #alias dir='dir --color=auto'
    #alias vdir='vdir --color=auto'
 
    alias grep='grep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias egrep='egrep --color=auto'
fi
 
# some more ls aliases
#alias ll='ls -l'
#alias la='ls -A'
#alias l='ls -CF'
 
# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
 
if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

You’ll notice at the bottom, if the .bash_aliases file exists, then Bash will include all aliases placed in that file for your shell. If you like cleanliness, I would suggest placing all your custom aliases in the .bash_aliases file. Otherwise, you are free to populate this file with any aliases you see fit.

Common Aliases

Here is a list of some common aliases I have come across:

alias ls='ls -aF --color=always'
alias ll='ls -l'
alias search=grep
alias mcd='mount /mnt/cdrom'
alias ucd='umount /mnt/cdrom'
alias mc='mc -c'
alias ..='cd ..'
alias ...='cd ../..'
alias L='ls -FLb' 
alias LL='ls -FLlb' 
alias a='alias' 
alias h='history' 
alias j='jobs -l' 
alias l='ls -Fb' 
alias la='ls -Flab' 
alias ll='ls -Flb' 
alias m='less' 
alias ot='popd' 
alias to='pushd' 
alias zm='zless'

If you need a more complex alias, by all means. I created an alias to check the memory usage of my mysql database:

alias memu="ps --user mysql u | grep mysql | awk '{print $4;}' | awk '{split($0,a,"."); print a[1]}'"

Remove Alias With ‘unalias’

If you are now tired with a specific alias, you may unalias that command.

$ unalias menu