CSS 432
Program 4: Domain Name Service
Professor: Joe McCarthy
Due date: See the syllabus
1. Purpose
This assignment is to design and code a program that
enables a server to check the integrity of a client
connection by looking for
IP address spoofing.
Through this assignment, you are going to learn how to use
functions for accessing the
Domain Name System (DNS),
such as getpeername, gethostbyaddr, and
for converting addresses, such as inet_ntoa,
ntohs, and inet_addr.
2. Algorithm
DNS is useful not only for resolving the IP address of a server
to which you would like to connect, but also for verifying the integrity of a
client that has contacted to your server.
Since the client information
within an IP packet includes only its source address and port number,
it is impossible to find who actually sent this packet. A malicious
client can even change its IP address and pretend to be someone
else. A solution to block out such a spoofing client is to refer its
IP address to a DNS server that retrieves this client's official host
name, aliases, and registered IP addresses.
Based on this concept, our spoofcheck.cpp program should behave
as follows:
- Use argv[1] in argument as the port to which
spoofcheck.cpp should bind itself.
- Instantiate a TCP socket.
- Go into an infinite loop (while (true) ...) where:
- Accept a new connection from a client through accept().
- Spawn a child process through fork().
The parent closes this connection and
goes back to the top of the loop, whereas the child
continues checking the integrity of this connection.
- Retrieve the client's IP address and port of this connection through
getpeername().
- Retrieve the client's hostent data structure through
gethostbyaddr().
- Retrieve the client's official name, aliases, and registered
IP addresses from the hostent.
- Decide whether this client is a honest or a spoofing client by
matching its IP address retrieved from getpeername()
and the list of addresses retrieved via gethostbyaddr().
(In other words, if you confirm that the client's IP address of this
connection matches one of the addresses listed in
hostent, you can trust this client.)
- Terminate this child process.
The following shows an example where spoofcheck was invoked
at uw1-320-20 on port 12345 while three different clients
- perseus, uw1-331-pc01, and metis - accessed this spoofcheck server.
The server printed out the client address and port retrieved from
getpeername() as well as its official hostname, aliases, and
a list of IP addresses retrieved from gethostbyaddr().
[css432@uw1-320-20 hw4]$ ./spoofcheck 12345
client addr = 216.186.75.3 port = 39329
official hostname: perseus.uwb.edu
alias: none
ip address: 216.186.75.3 ... hit!
an honest client
client addr = 216.186.75.144 port = 4252
official hostname: uw1-331-pc01.uwb.edu
alias: none
ip address: 216.186.75.144 ... hit!
an honest client
client addr = 216.186.72.14 port = 32848
official hostname: metis.uwb.edu
alias: metis
ip address: 216.186.72.14 ... hit!
an honest client
^c
[css432@uw1-320-20 hw4]$
3. Required Data Structures and Functions
To implement this spoofcheck program, you need to use the
following IP-related data structures and
DNS-related/address-conversion functions.
[Some of the links below are to web pages that offer more details on
the data structures and functions.
Note that the actual implementations of
these data structures and functions may differ across different Linux installations,
so you should always consult local man
pages for any data structures and functions as the ultimate authority.]
- int
getpeername(int s, struct sockaddr *name, socklen_t *namelen)
retrieves a pointer to information about the IP address (sockaddr name)
of the peer socket in the second argument.
The first argument is the socket file descriptor you have accepted from a client.
The third argument is a pointer to the length of the address name,
whose initial value should be a variable set to sizeof( name ).
Since the function retrieves address information (not a name, strictly speaking),
you may want to use variable names such as clientAddr and addrLen
that better indicate the actual information.
Also, since we are using IPv4, you should declare your name (or clientAddr)
variable of type sockaddr_in rather than sockaddr
(if we were using IPv6, you would use sockaddr_in6).
- struct sockaddr_in
the data structure you will receive
from getpeername(), (e.g., clientAddr in the
example above). To retrieve a client's IP address and port (in
sin_addr and sin_port), use inet_ntoa() and
ntohs() respectively.
#include <netinet/in.h>
struct sockaddr_in {
short sin_family; // e.g. AF_INET
unsigned short sin_port; // e.g. htons(3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
struct in_addr {
unsigned long s_addr; // load with inet_aton()
};
- struct hostent *
gethostbyaddr(const void *addr, int len, int type)
returns a pointer to the entry for a host (hostent) maintained by a DNS server.
The first argument should be an unsigned int addr of
a client IP address string that has been converted into
an unsigned integer through inet_addr().
The second and third arguments should be sizeof(
unsigned int ) and AF_INET respectively.
- struct hostent
the data structure returned by gethostbyaddr().
To retrieve the official name and aliases
of a given host, use the h_name and h_aliases fields.
To convert an address associated with a host, (i.e.,
h_addr_list[i]), use inet_ntoa().
#include <netdb.h>
struct hostent {
const char *h_name; /* official name of host */
char **h_aliases; /* alias list */
short h_addrtype; /* host address type */
short h_length; /* length of address */
char **h_addr_list; /* list of addresses from name server */
#define h_addr h_addr_list[0] /* address, for backward compatibility */
};
- uint16_t
ntohs(uint16_t netshort)
returns the argument value converted from network to
host byte order. Use this function to obtain a client's port number
from clientAddr.sin_port.
- in_addr_t
inet_addr(const char *cp)
converts a string-typed IP address, in the
standard IPv4 dotted decimal notation, to an integer value suitable
for use as an Internet address.
As noted above, you should use this function to convert the first
argument passed to gethostbyaddr().
- char *
inet_ntoa(struct in_addr in)
converts the Internet host address specified
by its argument struct in_addr in to a string in the Internet
standard dot notation. Use this function to obtain a string-typed IP
address from clientAddr.sin_addr and the
h_addr_list[] array in hostent.
4. Statement of Work
Code spoofcheck.cpp, compile it, and verify your
implementation. You may use Socket.h and
Socket.cpp in ~css432/hw1. For compilation, type:
g++ spoofcheck.cpp Socket.cpp -o spoofcheck
To test your program, run spoofcheck at any of uw1-320 Linux
machines, (say uw1-320-20) and thereafter login to any other machines
where you can initiate a client TCP connection to your
spoofcheck server through telnet. The following shows
an example test plan using the spoofcheck executable
that can be found in the ~css432/hw4 directory:
[css432@uw1-320-20 hw4]$ ./spoofcheck 12345
client addr = 216.186.75.196 port = 34433
official hostname: uw1-320-21.uwb.edu
alias: none
ip address: 216.186.75.196 ... hit!
an honest client
client addr = 69.91.201.104 port = 63442
gethostbyaddr error for the client( 69.91.201.104): 1
a spoofing client
The first lines of output above were generated by
testing from a separate xterm (on uw1-320-31):
[css432@uw1-320-31 ~]$ telnet uw1-320-20 12345
Trying 216.186.75.195...
Connected to uw1-320-20.uwb.edu (216.186.75.195).
Escape character is '^]'.
Connection closed by foreign host.
The second set of lines of output were generated by
launching PuTTY on a Windows computer on the UWB network
(selecting "Telnet" and specifying server "uw1-320-20" and port "12345"):
Try to establish a TCP connection from at least 3 different
computers on the UWB campus, one of which must be a Windows
machine.
Note that you cannot establish a TCP connection to UWB from off-campus
through any other ports than the well-known system ports such as 22
and 80. Therefore you don't have to - and cannot - conduct your
verification from off-campus.
In addition to your programming and verification work,
discuss the following three questions in your report:
- Your server, (actually each server process) terminates a client connection.
Does this server-initiated TCP disconnection cause any potential problems?
Why or why not?
- If a client resides in a private address domain
and thus tries to connect to your spoofcheck server through NAT,
can your server verify this client's integrity? Why or why not?
- If a client uses a dynamic IP address to be obtained from its DHCP server,
can your server verify this client's integrity? Why or why not?
5. What to Turn in
The homework is due at the beginning of class on the due date and
must be submitted via Catalyst Dropbox.
Criteria |
Percentage |
Documentation of your
spoofcheck.cpp in one page.
| 3pts(15%) |
Source code: that adheres good
function modularization, coding style, and an appropriate amount of
comments. The source code is graded in terms of
- correct discovery of a client IP address and port through
getpeername(), inet_ntoa() and ntohs(): 4pts
- correct discovery of a client official name, alias, and IP address(es) through the
gethostbyaddr() and hostent: 4pts
- comments: 2pts
|
10pts(50%) |
Execution output showing your server output for each test case.
You can use the script program suggested for
the first programming assignment to create the output file,
hw4.output.
Your output must verify the integrity of 3 different client
connections, one of which must be established from a Windows
machine. The output itself receives 1pt and each client verification
receives 1pt. |
4pts(20%) |
Discussions: should be given in
terms of three items: (1) a server-initiated TCP disconnection, (2) a
client's connection through NAT, and (3) a client's DHCP-generated
dynamic IP address, each receiving 1pt |
3pts(30%) |
Total |
20pts(100%) |
6. FAQ
This FAQ page may answer your questions. Click here.