Dude, Where's my System?
By Lew Pitcher
Recently, I changed over to an "always on" ADSL[1] connection from an
"on-demand" dialup one, and I now have an opportunity to host a
number of internet services from my home server. The one problem I
have is that, while my internet is "always on", my ISP occasionally
renegotiates the IP address of my ADSL connection, making my
internet services difficult to find. Up until now, I've played
"hide and seek" with my server, searching for it among a multitude
of alternate addresses each time my ISP changes the address.
Now, I could spend a bit of money to lease my own
domain name, and subscribe to one of those 'dynamic DNS' services
that let you point your domain name at an ever-changing IP address,
but I don't need a permanent domain name right now, and I've got other
options.
My ISP provides web site hosting for their subscribers, with the
usual upload and download volume caps to discourage extensive web
hosting. I don't need their host for my content, but it
does make a handy 'rendezvous' site to gain access to my
system. All I have to do is arrange for my PPPoE[2] client[3] to rewrite my
personal web page on my ISP's server every time my ISP gives me a
new IP address. If PPPoE can populate that web page with my
system's new IP address, I'll always be able to find my system from
the outside by looking at my webpage on my ISP's server.
Simple, yes?
Simple, yes!
The first thing I needed to do was to arrange for my PPPoE
client to be able to pass each new IP address on to something that
would update my external webpage.
To do this, I modified my /etc/ppp/ip-up[4] script to
execute a new script (/etc/ppp/ip-up.webpage),
passing it the PPP 'local' address assigned by my ISP to my end of
my PPPoE ADSL connection. The /etc/ppp/ip-up script
would then write the webpage and get it to my ISP.
This was a simple change (a literal 'one-liner') in
/etc/ppp/ip-up
#!/bin/sh
#
# ip-up interface-name tty-device speed local-IP remote-IP ipparm
# $1 $2 $3 $4 $5 $6
#
# (NB: ipparm is string from ipparm parameter in pppd options)
#
# This file /etc/ppp/ip-up is run by pppd when there's a
# successful ppp connection.
#
# The environment is cleared before executing this script
# so the path must be reset.
#
PATH=/usr/bin:/usr/sbin:/usr/local/bin:/sbin:/bin
export PATH
#
umask 033
echo "$4" >/var/run/$1.ip
#
#
# Build redirect webpage, put it on ISP's webserver
/etc/ppp/ip-up.webpage "$4"
#
/usr/bin/logger -i -t /etc/ppp/ip-up "$1 [$4] connected to ISP [$5]"
# Done...
The Harder Part
Now that I had arranged for my PPPoE client to run a script, I
had to build the script it would run. The script would have to
build an HTML document that would redirect the reader to my
server's IP address, and FTP that document to my ISP's web server.
It would have to preserve the internal security of my system by
refraining from exposing my ISP userid and password to local users,
and should do this with simple tools and a minimum of
programming.
The security aspects were satisfied by making the script
'execute only'[5], so no local user could read it's
contents, and by ensuring that no password was exposed to
ps(1)[6,7] as a command line argument. The HTML
was built through a simple "here document"[8] fed into a
cat(1)[9] command that created a temporary
file of HTML. The new IP address was written into the HTML through
the shell variable substitution process that occurs with "here
document" processing. Finally, the temporary file was transmitted
to my ISP using a command line ftp(1)[10] command, with
its parameters all passed through another "here document".
This second "here document" permitted me to pass the user name and
password into the FTP client without exposing them on a command
line.
The /etc/ppp/ip-up.webpage
script (below) is primitive and not very elegant, but it gets the
job done.
#!/bin/bash
# Validate that we get 1 and only 1 parameter
case $# in
1) ;;
*) /usr/bin/echo Usage: $0 ip-address-or-dns-name
exit 1 ;;
esac
# the $1 parameter is the IP address assigned to our system
# Establish today's date (for html)
DATE=`/usr/bin/date`
# allocate empty tempfile, terminate if unable to allocate
TEMPFILE=`/usr/bin/mktemp /tmp/$1=XXXXXX` || exit 2
# build webpage (redirect) html into tempfile
# NB: $1 is our local IP address, passed in from ip-up
# $DATE is the current date and time
# With the "here document", these variables will
# be substituted into the stream by the shell
/usr/bin/cat >$TEMPFILE <<END
<html>
<head>
<!-- $DATE -->
<meta http-equiv="refresh" content="0;url=http://$1/">;
</head>
</html>
END
# send webpage (redirect html) to webserver
# ISP_ADDRESS is FTP address of ISP's web server
# ISP_USERID is my userid at ISP's FTP server
# ISP_PASSWD is my password at ISP's FTP server
# NB: ISP_USERID, ISP_PASSWD set as local environment
# vars so that they don't appear as parameters
# in local 'ps ax' listings
# With the "here document", these variables will
# be substituted into the stream by the shell
ISP_ADDRESS=webserver.isp.com
ISP_USERID=username
ISP_PASSWD=password
/bin/ftp -n <<STOP
open $ISP_ADDRESS
user $ISP_USERID $ISP_PASSWD
ascii
put $TEMPFILE index.htm
bye
STOP
# delete tempfile
/bin/rm -f $TEMPFILE
# terminate
exit 0
Olly-olly, Outs in free!
Now, when my ISP changes my IP address, my PPPoE server invokes
/etc/ppp/ip-up, giving it my new IP address. This
script invokes my /etc/ppp/ip-up.webpage script,
which builds and installs a redirect webpage at my ISP's webserver
that points at my new IP address. All I have to do is
browse a specific web page on my ISP's webserver, and I'll be
redirected to my webpage on my server.
So, with a little scripting, and the resident automation in my
Linux system, I've now got a way to find my server from the
outside, no matter which IP address my ISP gives it. I guess you
could say that my server has given up the game of "hide and seek",
and is playing other games now.
Footnotes
- [1] -
ADSL
- ADSL (or "Asymmetrical Digital Subscriber Line") is a
technology that permits an ISP to offer high speed internet
connectivity over regular phone lines without impacting
the regular use of the phone line. In other words, I can surf the
internet while my wife chats with her friends over the
phone.
- [2] -
PPPoE
- PPPoE (or "PPP over Ethernet") is a low level protocol that
some ISPs use to deliver TCP/IP connectivity on ADSL lines. Since
PPPoE uses PPP (the regular 'dial up' services) to manage the ADSL
connection, all the PPP facilities and management tools work with a
PPPoE-enabled ADSL line. This includes things like the
/etc/ppp/ip-up script.
- [3] - my
PPPoE client
- is the "Roaring Penguin" PPPoE daemon that can be found at http://www.roaringpenguin.com/penguin/open_source_rp-pppoe.php.
In the Slackware 9.0 Linux distribution that I run, the Roaring
Penguin PPPoE daemon is contained in the
rp-pppoe-3.5-i386-1.tgz package. However, to use this
PPPoE daemon, you also need a PPP daemon; Slackware 9.0 uses the
ANU PPP daemon found at ftp://cs.anu.edu.au/pub/software/ppp/,
and in Slackware package ppp-2.4.1-i386-2.tgz.
- [4] -
/etc/ppp/ip-up
- The /etc/ppp/ip-up script is executed by the PPP
daemon when ever it establishes a TCP/IP environment over the PPP
link. Several parameters are given to the ip-up script,
including the IP address assigned to our end of the PPP connection.
I use this script to trigger the construction of the web page that
gets placed on my ISP's server, and I use the supplied IP address
in the contents of the web page.
- [5] -
"execute only"
- Scripts, like other executable files, can be set to be
executable without being readable by using a
"chmod ug=x scriptname" command. I want
this because I don't want users on my system to be able to snoop
through the text of the script to find my logon and password.
- [6] -
xx(y) notation
- Ancient Unix notation that indicates the documentation for
topic xx can be found in section y
of the printed or online manual. Most Linux users can read this
documentation using the "man y xx" syntax from
the command line, as in "man 1 ps".
- [7] -
ps(1)
- ps lists the particulars of all running processes. If
given the correct options, it will show the entire command line
used to invoke the process. I avoid placing userids and passwords
into command lines as someone could snoop them out by running
ps at the proper moment. Call me paranoid, but even
paranoids have enemies. ;-)
- [8] - "here
document"
- A "here document" is a special form of redirection that routes
text embedded in a script directly into a program's input. The
shell can perform parameter expansion, command substitution, and
arithmetic substitution on the contents of the "here document"
before the resulting text is given to the program. This makes "here
documents" ideal for my use, because I can have the shell customize
the text as necessary without depending on complex editor
commands.
- [9] -
cat(1)
- cat is a utility that concatenates files
together, and outputs the resulting file to stdout. If no input
files are named, cat will read it's input from stdin. This
feature makes cat a handy, but dumb, text editor, and
that's how I use it here.
- [10] -
ftp(1)
- The command line FTP client works in this environment, but it
would have been better if it had some scripting ability. I use a
"here document" to pass in the FTP commands, so as to avoid
exposing my ISP access password on the command line. However, with
the "here document" approach, the ftp(1) client won't
abort the interaction if an FTP command goes wrong, and there is no
way to detect or act on a command failure from within the "here
document". So, I take a chance that the FTP script will work each
and every time without fail.
Canadian by birth, and living in Brampton, Ontario, I am a career techie
working at a major Canadian bank. For over 25 years, I've programmed on
all sorts of systems, from Z80 CP/M up to OS/390. Primarily, I develop
OS/390 MVS applications for banking services, and have incorporated
Linux into my development environment.
Copyright © 2004, Lew Pitcher. Released under the Open Publication license
unless otherwise noted in the body of the article. Linux Gazette is not
produced, sponsored, or endorsed by its prior host, SSC, Inc.
Published in Issue 105 of Linux Gazette, August 2004