Lab 1: Charlie on the MTA
Due: 11:00am, Tuesday, April 5th, 2005
Preliminaries
Your task for this assignment is to write a simple Mail Transfer Agent
(MTA). An MTA is a program that relays email messages between
senders, receivers, and possibly other MTAs. MTAs are the servers
that process email messages in the Internet, passing them from the
sender's email client---or Mail User Agent (MUA)---and the receiver's
mail delivery agent. By far the most common MTA in use on the
Internet is the infamous sendmail program. Most of
sendmail's notoriety comes from its incredible complexity and
resulting never-ending discovery of security vulnerabilities. Don't
despair; your MTA will be considerably simpler, although not
necessarily any easier to debug!
The reason you're writing an MTA is not to build a replacement for
sendmail (although the Internet could badly use one!), but rather to
learn about how complex Internet servers are constructed. Initially,
we'll start off simple with a single-threaded server that can only
process one mail message at a time. It should be able to accept a
mail message from a MUA, forward the message on to its destination,
and then prepare to accept the next mail message. We'll fix this
limitation as part of Lab 2.
Specification
Your MTA will use the Internet-standard Simple Mail Transfer Protocol
(SMTP) to exchange mail messages. SMTP is documented in RFC 2821,
but you'll only need to implement a small subset of the commands
listed below. You will not need to handle local delivery of mail
messages. Instead, your MTA will only forward email messages on to
another MTA for actual delivery.
You are responsible for the following requirements:
- Your MTA is able to properly receive a message from a
well-behaved MUA like Netscape, Outlook Express, or Mozilla. This
will require you to support the following SMTP commands: HELO, MAIL,
DATA, RCPT, QUIT, and RSET.
- You must support the use of dotted-quad IP addresses instead of
domain names in both the HELO, MAIL, and RCPT commands.
- You may not use the fork() system call.
- You do not need to handle messages with more than 255
recipients.
- You do not need to handle mail messages larger than 65535
bytes.
You do not need to bother with the following things. You should just
ignore them as best you can.
- You don't need to support local destinations or source-routed
messages. If the argument to the RCPT TO: command is not of the form
user@domain.name (where domain.name could also be a dotted-quad IP
address), you should refuse to accept the message.
- You don't need to queue messages that cannot be delivered. Any
destination address that is unable to accept the message immediately
(after trying all the MX options--see below) should be treated as a
delivery failure, and an "undeliverable mail" notification should be
returned to the sender immediately.
- Any other SMTP commands like EXPN, VRFY, HELP, ETRN, NOOP, or
VERB. You may simply return an error message if your MTA receives one
of these commands.
- ESMTP extensions. You do not need to recognize EHLO or any of the
additional parameters to standard SMTP commands.
- You do not need to implement the data transparency procedure
described in Section 4.5.2 of the RFC. Basically, you can assume your
MTA will never receive a message with a period as the first character of a
line.
- You should ignore all headers in the DATA portion of the message.
Further, you do not need to implement any sort of loop detection.
If you are able to send a simple email message using your MTA, you're
in good shape.
A sample mail transaction
SMTP is a simple client/server protocol that runs over TCP. A client
(either an MUA or an MTA) opens a TCP connection to an MTA, identifies
itself, specifies the recipients of the message, sends the contents
of the message, and quits. The server processes the message and
forwards it on to the destinations specified using the same procedure.
You can play with a real, live MTA yourself. The UCSD campus has an
MTA running on smtp.ucsd.edu.
% telnet smtp.ucsd.edu 25
This opens a TCP connection to port 25 (the well-known SMTP port) on
smtp.ucsd.edu. You should see:
Trying 132.239.1.49...
Connected to smtp.ucsd.edu.
Escape character is '^]'.
220 smtp.ucsd.edu ESMTP Sendmail 8.12.9/8.9.3; Thu, 3 Apr 2003 10:53:59 -0800 (PST)
The first three lines are output from the telnet program. The last is
the greeting sent by the MTA (Sendmail, surprise, surprise) at
smtp.ucsd.edu.
You can then identify yourself using the HELO command:
HELO dungeonsofdespair.com
and the MTA returns
250 smtp.ucsd.edu Hello fast.ucsd.edu [132.239.15.4], pleased to meet you
Where fast.ucsd.edu is the machine you're actually using. Pretty
smart MTA, huh? So much for trying to fool it---at least at this
stage. We can now ask it to deliver a message for us:
MAIL FROM:<223bstudent@ucsd.edu>
and it responds:
250 2.1.0 <223bstudent@ucsd.edu>... Sender ok
Now, we'll try sending ourselves a message:
RCPT TO:<223baccount@ucsd.edu>
You should obviously replace 223baccount@ucsd.edu with your own
account name.
250 2.1.5 ... Recipient ok
Note that if you use an account not at UCSD, and you're connecting
from a machine outside of UCSD, you'll get a message like:
550 5.7.1 ... Relaying denied
Seems UCSD doesn't want to be bothered with handling other people's
mail. By now you're probably starting to understand why sendmail is
so complicated. Luckily we're going to ignore all of these details in
our MTA. Now, send your message:
DATA
This is a sample message.
.
Note that you must end your message with a . on a line by itself. The
server responds with:
250 2.0.0 h33J23M4002993 Message accepted for delivery
Great. Now we can log off.
QUIT
221 2.0.0 smtp.ucsd.edu closing connection
Connection closed by foreign host.
If everything went well, you've now got mail! That's all there is to
it. Of course, what happened behind the scenes is that smtp.ucsd.edu
connected to the MTA at your mail server and repeated this whole
process in an automated fashion. That server then moved the mail to
your local mail spool. We're not going to worry about how that last
step happens.
Building your MTA
The first thing you should do, if you're not already comfortable with
sockets programming, is check out MIT's excellent Using TCP through Sockets tutorial.
We have provided an initial skeleton directory to get you started. It
is available as /home/classes/sp05/cse223b/labs/lab1.tgz on the
Active web machines. You should copy this file to your working
directory. The following sequence of commands should extract the
files and build the initial (useless) executable:
% tar xzf lab1.tgz
% cd lab1
% gmake
The tarball contains four files: domain.c, domain.h, Makefile, and
mta.C. You'll find the first two files useful for looking up the
destination MTA for messages you're trying to deliver (see the following
section on mail exchangers). The Makefile,
as the name implies, is a GNU makefile that builds the executable. (If
you are trying to build on Linux, you should follow the directions in
the comments about how to edit the Makefile.)
You shouldn't need to know anything about make to use it, but if
you're curious, the documentation is
on-line. The last file, mta.C, is the one you're going to use to
write your MTA. Currently, it just accepts TCP connections, closes
them, and waits for another. You can run the executable by typing:
% ./mta 2225
Where 2225 is the port you want it to listen on. In order not to
conflict with the already running MTA (sendmail), you should run your
MTA on a port other than 25 (larger than 1024). During testing you're
likely to want to use something other than 2225 as well so it doesn't
conflict with other students working on their projects.
Mail exchangers
When determining where to send messages to, it would be nice if you
could just contact the destination directly. Unfortunately, many
domains have mail exchangers that receive mail. This is especially
important for you to know, as cs.ucsd.edu, the domain many of you use
for your email accounts, is NOT handled by a machine called
cs.ucsd.edu. Instead, there are four machines set up to handle mail for
the cs.ucsd.edu domain. These are stored in so-called MX records in
the DNS. You can see for yourself using the dig command:
% dig cs.ucsd.edu mx
; <<>> DiG 8.3 <<>> cs.ucsd.edu mx
;; res options: init recurs defnam dnsrch
;; got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 2
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 4, ADDITIONAL: 16
;; QUERY SECTION:
;; cs.ucsd.edu, type = MX, class = IN
;; ANSWER SECTION:
cs.ucsd.edu. 2D IN MX 10 fast.ucsd.edu.
cs.ucsd.edu. 2D IN MX 10 gradlab.ucsd.edu.
cs.ucsd.edu. 2D IN MX 20 mailbox.ucsd.edu.
cs.ucsd.edu. 2D IN MX 50 tartarus.ucsd.edu.
...
As you can see, fast, gradlab, mailbox, etc... are the machines that
you should actually contact to send mail to a user at cs.ucsd.edu.
Which one you choose is up to you, but it may be the case that one or
more of them (fast, for example) isn't functioning when you try to
send the message. In that case, you should try each entry in the list
in turn.
Because MX processing is complicated business, we've provided some
code for you, in domain.c, that will handle the difficult parts.
getmxrr() will return an ordered list of machines that you can try to
deliver mail to for a given domain. mta.C includes some sample code
showing you how to use it.
Testing your MTA
The easiest way to test and debug your MTA is to use it interactively
just as we did above. Of course, once your MTA accepts messages,
you'll need to send them on. I'd suggest trying to send messages to
yourself so you can see if it actually succeeds! You might find
programs like Ethereal and Netcat (nc) useful to follow the communication between
your MTA and others.
Once you think your MTA is working, you can hook it up to a real
MUA and give it a whirl. The simplest way is to use your normal mail
reader (Eudora, Netscape, Mozilla, Outlook Express, etc.) and just
configure it to use your MTA rather than your default one.
For Mozilla, you can do this by going to Edit->Mail and Newsgroup
Account Settings and selecting the Outgoing Server (SMTP) tab. Enter
the name of the machine your MTA is running on (e.g., trowel.ucsd.edu)
and port 2225. Make sure you turn off SSL (Never) and uncheck the
user name and password option.
Similar changes can be made to other mailers. I'll post them here if
anyone wants to email me how to do this in your own mail reader.
Collaboration policy
All code for this assignment must be written individually. You
are not allowed to look at anyone else's solutions or solutions to
similar assignments you may find for courses at UCSD or other
institutions. You may discuss the assignment with fellow students,
but all code you submit must be either yours alone or code that was
provided to you as part of the assignment.
Turnin procedure
The Makefile distributed in the lab tarball has the ability to tar up all of the
files in your directory. One consequence of this is that you should
make sure that all the files I need to compile your code are in this
directory. You might take this opportunity to include a README file
or somesuch giving me any instructions I might need about how to run
your code, known bugs, etc., etc. Do not modify the Makefile to
link in code outside of the working directory. When you're ready
to submit your code, you can execute the following command:
% gmake turnin
which will create a file called lab1-turnin.tgz. You might verify your tarball
contains all the right things in the following fashion.
% mkdir tmp
% cd tmp
% tar xzf ../lab1-turnin.tgz
% make
If all goes well, you're ready to submit your assignment. To do that,
you'll need to create a directory called 223bturnin in your home directory on the Active web
machines and copy the tarball into it. The following commands will do
this for you.
% mkdir ~/223bturnin
% cp lab1-turnin.tgz ~/223bturnin
That's it. I'll come along and copy the file out of your directory.
You do NOT need to make the file world-readable. In fact, please
don't, as you'll make it all-to-tempting for somebody to take a peek
at your assignment. I will consider the first file in the turnin
directory after the deadline to be your submission. Copying over that
file with a new version after the due date won't do you any good, so
don't bother.
If you'd like credit for your assignment, please make sure you are
registered for the course. I will only check for submissions from the
students listed on the class roll on Student Link (and those students
enrolled through the extension school---you should know who you are,
as you've been assigned the funny cse223b## Active web accounts). If,
for some reason, you're worried I don't know you're enrolled in the
class, send me email.