I was reading Wikipedia articles about things like the interplanetary internet, InterPlaNet and delay-tolerant networking. After writing a post on serving web content with tor, I wanted to try to serve a web page over ION-DTN. This post covers installing ION-DTN 3.4.0 on FreeBSD.

After the installation instructions, there are a few usage examples, including a very crude scripted web server. The original goal was to take an outside web request, send it over ION-DTN to a server on the other side and return the response. That example deserves a separate post.

Special thanks to Scott C Burleigh for helping me work through some setup problems.

The following are follow ups to this post:

Software Versions

$ date
February 8, 2016 at 03:34:50 PM JST
$ uname -vm
FreeBSD 11.0-CURRENT #0 r287598: Thu Sep 10 14:45:48 JST 2015 root@:/usr/obj/usr/src/sys/MIRAGE_KERNEL amd64
$ ionadmin
: v
ION OPEN SOURCE 3.4.0

Instructions

First, download and extract the source code.

wget 'http://downloads.sourceforge.net/project/ion-dtn/ion-3.4.0b.tar.gz'
tar -zxvf ion-3.4.0b.tar.gz
cd ion-open-source/

Note that ION-DTN requires gmake and bash. autotools are not required but useful.

portmaster devel/gmake shells/bash devel/autotools

The sysctl_script.sh script needs to be patched to build IOT-DTN run on FreeBSD. A number of other files also need to be patched work properly. These scripts appear to be written for Linux and use #!/bin/bash instad of #!/usr/bin/env bash.

sed -i '' 's:#!/bin/bash:#!/usr/bin/env bash:' sysctl_script.sh
find ./ -type f -print0 | xargs -0 sed -i '' 's:#!/bin/bash:#!/usr/bin/env bash:'

Some of the shared memory values suggested by sysctl_script.sh are too low on FreeBSD. Copy the following lines into /boot/loader.conf. These values are read only tunable and must be set before the system enters multi-user mode.

kern.ipc.shmmni=192
kern.ipc.shmseg=128
kern.ipc.semmns=32000
kern.ipc.semmni=128

Copy the following lines into your choice of /boot/loader.conf or /etc/sysctl.conf. These values are tunable in multi-user mode. See the chapter in the FreeBSD Handbook for more information.

kern.ipc.shmmax=536870912
kern.ipc.shmmin=1
kern.ipc.shmall=131072
net.inet.udp.maxdgram=32000
kern.ipc.shm_use_phys=0
kern.ipc.shm_allow_removed=0

Note that the above tunable values can be changed by root at runtime.

su
sysctl kern.ipc.shmmax=536870912

Reboot the system so the new shared memory values will take effect.

su
shutdown -r now

Read README.txt. Optionally run ./config -h. When you know what you are doing, configure and build.

System Wide Install

A system wide installation needs to be performed by root. I also run the build as root because I ultimately want root to be the owner of the installed files. Note that by default the man pages are installed in the wrong place on FreeBSD.

su
./configure --mandir=/usr/local/man
gmake clean
gmake

Test the build. gmake test should work, but it is configured to test the original Bundle Security Protocol. The depreciated bsp tests are skipped, so running gmake test is pointless. Instead, Run the following command. It tests the new not yet standardized Streamlined Bundle Security Protocol.

(cd tests/; ./runtests sbsp/)

If the tests pass, perform a system wide install as root.

gmake install
ldconfig

Single User Install

A single user install can be performed by passing the –prefix flag to configure.

./configure --prefix="$HOME/ion" --mandir="$HOME/ion/man"
gmake clean
gmake
(cd tests/; ./runtests sbsp/)
gmake install

Appended ion/bin to PATH. If ion/bin is in $PATH then manpath will look for manpages in ion/man.

~/.profile

export "PATH=$HOME/ion/bin:$PATH"

The ion library path could be added to LD_LIBRARY_PATH, but running ldconfig requires root privileges, so this does not make sense for a single user install. See this link for details.

Documentation

Serve tutorial.html and open it in your favorite browser. Read through the tutorial.

FILE="tutorial.html"; { printf "HTTP/1.0 200 OK\r\nContent-Length: $(wc -c <"$FILE")\r\n\r\n"; cat "$FILE"; } | nc -N -l 0.0.0.0 8080

Also look at ION Deployment Guide.pdf and ION.pdf. Note the AMS programmer’s guide v2.2.pdf and the Windows related PDFs. On a system wide install, there are a bunch of useful resources in /usr/local/share/ion/. Finally, man ion.

FILE="ION Deployment Guide.pdf"; { printf "HTTP/1.0 200 OK\r\nContent-Length: $(wc -c <"$FILE")\r\n\r\n"; cat "$FILE"; } | nc -N -l 0.0.0.0 8080
FILE="ION.pdf"; { printf "HTTP/1.0 200 OK\r\nContent-Length: $(wc -c <"$FILE")\r\n\r\n"; cat "$FILE"; } | nc -N -l 0.0.0.0 8080
ls /usr/local/share/ion/
man ion

Starting ION

A number of configuration files are required to start ION. Add the following lines to the specified files. It is probably a good idea to move to a different directory first.

host1.ionrc

1 1 ''
s
a contact +1 +3600 1 1 100000
a range +1 +3600 1 1 1
m production 1000000
m consumption 1000000

host1.ltprc

1 32
a span 1 32 32 1400 10000 1 'udplso localhost:1113'
s 'udplsi localhost:1113'

host1.bprc

1
a scheme ipn 'ipnfw' 'ipnadminep'
a endpoint ipn:1.0 q
a endpoint ipn:1.1 q
a endpoint ipn:1.2 q
a protocol ltp 1400 100
a induct ltp 1 ltpcli
a outduct ltp 1 ltpclo
s

host1.ipnrc

a plan 1 ltp/1

host1.ionsecrc is not required, but it keeps “Can’t find ION security database.” from being logged in ion.log.

1

Create host1.rc with the following command.

ionscript -i host1.ionrc -s host1.ionsecrc -l host1.ltprc -b host1.bprc -p host1.ipnrc -O host1.rc

Start ION with either of the following commands.

ionstart -I host1.rc
ionstart -i host1.ionrc -s host1.ionsecrc -l host1.ltprc -b host1.bprc -p host1.ipnrc

ION can be stopped with the following command.

ionstop

Examples

The following examples can be used to get started.

Hello World

Enter the follow lines into the terminal. Hit ^C to exit bpsink after verifying the payload has been delivered.

echo "Hello, World!" | bpsource ipn:1.1
bpsink ipn:1.1
# ^C to exit bpsink

A slightly unreliable single line hello world example is below.

{ echo "Hello, World!"; sleep 1; } | bpchat ipn:1.1 ipn:1.1

Chat

Use two terminals to enter the following commands. Enter text and hit enter to transfer the line to the other terminal. Hit ^C to exit.

# α terminal
bpchat ipn:1.1 ipn:1.2
# ^C to exit bpchat

# β terminal
bpchat ipn:1.2 ipn:1.1
# ^C to exit bpchat

Echo Loop

This modified chat example sets up an echo server. The server echoes lines back to the client until it receives EOT on a single line. EOT is piped into the connection after the client is closed with ^C. The server closes automatically without any manual intervention.

# α terminal
mkfifo fifo
bpchat ipn:1.1 ipn:1.2 <fifo | sed -u -n "/^$(printf "\4")$/q; p" | tee fifo

# β terminal
bpchat ipn:1.2 ipn:1.1; printf "\4\n" | bpchat ipn:1.2 ipn:1.1
# ^C to exit bpchat

Scripted Request-Response: Serving a Web Page Over BP

This is a crude example of using bpsendfile and bprecvfile to serve a web page over BP. First, create index.html. Alternatively, use tutorial.html or another file.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Hello World!</title>
</head>
<body>
<p>Hello World!</p>
</body>
</html>

Add the following to server.sh. The request is written to testfile1. It also moonlights as the file to be sent.

#/bin/sh

SOURCE=ipn:1.1
DESTINATION=ipn:1.2
SERVICE_CLASS=0.1
FILE=index.html
CONTENT_TYPE=text/html

while true; do
echo "<<<$((X=X+1))<<<"
bprecvfile $SOURCE 1
REQUEST=$(cat testfile1)
echo "$REQUEST"
# in a real server, do something with the request
echo ">>>${X}>>>"
BODY=$(cat $FILE)
RESPONSE=$(cat <<EOF
HTTP/1.0 200 OK
Content-Type:
${CONTENT_TYPE}
Content-Length:
$((${#BODY}+1))
Connection: close

${BODY}
EOF
)
echo "$RESPONSE"
echo "$RESPONSE" > testfile1
bpsendfile $SOURCE $DESTINATION testfile1 $SERVICE_CLASS
done

Add the following to request.sh. This script is much like server.sh, but without the loop.

#/bin/sh

SOURCE=ipn:1.2
DESTINATION=ipn:1.1
SERVICE_CLASS=0.1

echo "<<<$((X=X+1))<<<"
REQUEST=$(cat <<EOF
GET / HTTP/1.1
Host: www.host.com
Connection: close

EOF
)
echo "$REQUEST"
echo "$REQUEST" > testfile1
bpsendfile $SOURCE $DESTINATION testfile1 $SERVICE_CLASS
echo ">>>${X}>>>"
bprecvfile $SOURCE 1
RESPONSE=$(cat testfile1)
echo "$RESPONSE"

From different terminals, start the server and make a request. Note that request.sh is run in the current shell so that the request number increases if the command is executed multiple times.

chmod +x server.sh request.sh

# α terminal
./server.sh

# β terminal
. ./request.sh

Unresponsive ION

If ION becomes unresponsive, restart it. This example abuses ION. Enter the following in badserver.sh.

#/bin/sh

SOURCE=ipn:1.1
DESTINATION=ipn:1.2
FILE=index.html
CONTENT_TYPE=text/html

while true; do
BODY=$(cat $FILE)
RESPONSE=$(cat <<EOF
HTTP/1.0 200 OK
Content-Type:
${CONTENT_TYPE}
Content-Length:
$((${#BODY}+1))
Connection: close

${BODY}
EOF
)
echo "---$((X=X+1))---"
echo "$RESPONSE" | bpchat $SOURCE $DESTINATION
done

Let badserver.sh run until the hello world example stops working.

# α terminal
chmod +x badserver.sh
./badserver.sh

# β terminal
echo "Hello, World!" | bpsource ipn:1.3
bpsink ipn:1.3
# ^C to exit bpsink

Receive the data sent from badserver.sh.

bpsink ipn:1.2
# ^C to exit bpsink

Hold ^C to kill the badserver.sh script. Stopping ION may help badserver.sh die faster. Restart ION and the hello world example should work agian.

ionstop
ionstart -I host1.rc
echo "Hello, World!" | bpsource ipn:1.3
bpsink ipn:1.3
# ^C to exit bpsink

If ionstart or ionstop hangs, run killm directly and restart ion.

killm
ionstart -I host1.rc

write failed, filesystem is full

Congratulations! ion.log probably ate up all of your disk space. Delete it.

rm ion.log

References: