Socket Options
Let's look at socket options:
 
     #include <sys/types.h>
     #include <sys/socket.h>
 
     int getsockopt(int s, int level, int optname, char *optval,
          int *optlen);
     int setsockopt(int s, int level, int optname,
          const char *optval, int optlen);
 
Example:
 
    int     one = 1;
    if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof(one)) < 0)
            printf("error...");
 
  - When manipulating socket options, the  level  at  which  the
    option resides and the name of the option must be specified.
 
  - To manipulate options at the "socket" level, level is speci-
    fied  as  SOL_SOCKET.   To  manipulate  options at any other
    level, level is the protocol number  of  the  protocol  that
    controls  the  option.   For  example,  to  indicate that an
    option is to be interpreted by the TCP  protocol,  level  is
    set to the TCP protocol number (see getprotobyname(3N)).
 
  - The parameters optval and optlen are used to  access  option
    values  for setsockopt().  For getsockopt(), they identify a
    buffer in which the value(s) for the requested option(s) are
    to  be returned.
 
  - Most socket-level options take an int for optval.  For  set-
    sockopt(), the optval parameter should be non-zero to enable
    a boolean option, or zero if the option is to  be  disabled.
 
  - SO_LINGER  uses a struct linger parameter that specifies the
    desired state of the option and  the  linger  interval  (see
    below).  struct linger is defined in .  struct
    linger contains the following members:
 
     l_onoff             on = 1/off = 0
     l_linger            linger time, in seconds
 
  - The following options are recognized at  the  socket  level.
 
     SO_REUSEADDR        enable/disable local address reuse
 
     SO_KEEPALIVE        enable/disable   keep   connections
                         alive
 
     SO_DONTROUTE        enable/disable routing  bypass  for
                         outgoing messages
                         It indicates that outgoing messages
                         should bypass the  standard routing
                         facilities.   Instead, messages are
                         directed to the appropriate network
                         interface according to the network
                         portion of the destination address.
 
     SO_LINGER           linger on close if data is present
 
     SO_BROADCAST        enable/disable    permission     to
                         transmit broadcast messages
 
     SO_OOBINLINE        enable/disable  reception  of  out-
                         of-band data in band.  When set,
                         OOB data is treated like normal data.
 
     SO_SNDBUF           set buffer size for output
 
     SO_RCVBUF           set buffer size for input
 
     SO_TYPE             get the type  of  the  socket  (get
                         only)
 
  - SO_LINGER controls the action taken when unsent messages are
    queued  on  a  socket  and  a close(2) is performed.  If the
    socket promises reliable delivery of data and  SO_LINGER  is
    set,  the  system  will  block  the  process  on the close()
    attempt until it is able to transmit the data  or  until  it
    decides  it  is unable to deliver the information (a timeout
    period, termed the linger interval, is specified in the set-
    sockopt()  call  when SO_LINGER is requested).  If SO_LINGER
    is disabled and a close() is issued, the system will process
    the  close() in a manner that allows the process to continue
    as quickly as possible.
 
  - The option SO_BROADCAST requests permission to  send  broad-
    cast  datagrams  on the socket.  With protocols that support
    out-of-band data,  the  SO_OOBINLINE  option  requests  that
    out-of-band data be placed in the normal data input queue as
    received; it will then be accessible with recv()  or  read()
    calls without the special MSG_OOB flag.
Protocols
 
Let's modify the client implementation of homework 2 to fork a
child to do the read, and to go to an arbitrary port.
 
/********************************************************************
 *                                                                  *
 *             Client implementation for Homework 2, modified       *
 *             to go to any port                                    *
 *                                                                  *
 ********************************************************************/
 
#include <stdio.h>
#include <netdb.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
 
main(argc, argv)
int argc;
char **argv;
{
   int fd;               /* fd into transport provider            */
   int continuation = 0; /* used to process long input strings    */
   char buf[BUFSIZ];     /* input string and response from server */
 
   int nbytes;        /* The number of bytes read from the server */
   int done;          /* tells when we read the entire string     */
   int where;         /* current position in read buffer          */
   int length;        /* the length of the input string           */
 
   struct sockaddr_in myaddr;   /* address that client uses       */
   struct sockaddr_in servaddr; /* the server's full addr         */
   struct hostent *hp;          /* holds IP address of server     */
 
   void handler();
 
   sigset(SIGCHLD, handler); 
 
   /*
    *  Check for proper usage.
    */
   if (argc != 3) {
      (void) fprintf(stderr, "Usage: %s host port\n", argv[0]);
      exit(2);
   }
 
   /*
    *  Get a socket into TCP/IP.
    */
   if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
      perror("socket failed!");
      exit(1);
   }
 
   /*
    *  Bind to an arbitrary return address.
    */
   bzero((char *)&myaddr, sizeof(myaddr));
   myaddr.sin_family = AF_INET;
   myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
   myaddr.sin_port = htons(0);
 
   if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
      perror("bind failed!");
      exit(1);
   }
 
   /*
    *  Fill in the server's address and the data.
    */
   bzero((char *)&servaddr, sizeof(servaddr));
   servaddr.sin_family = AF_INET;
   servaddr.sin_port = htons(atoi(argv[2]));
 
   hp = gethostbyname(argv[1]);
   if (hp == 0) {
      (void) fprintf(stderr, "could not obtain address of %s\n", argv[2]);
      exit(1);
   }
 
   bcopy(hp->h_addr_list[0], (caddr_t)&servaddr.sin_addr, hp->h_length);
 
   /*
    *  Connect to the server.
    */
   if (connect(fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
      perror("connect failed!");
      exit(1);
   }
 
   switch (fork()) {
      case -1:
          perror("fork failed!\n");
          exit(1);
 
      default: /* parent */
 
         /*
          *   Read data from the user and send it to the server
          */
         for (;;) {
            if (fgets(buf, BUFSIZ, stdin) == NULL) {
               (void) fprintf(stderr, "abnornal termination\n");
               exit(1);
            }
 
            /*
             *  If the last character is not a new-line, then the user
             *  is entering a very large string.  So, go back and get the
             *  rest of the user data.
             */
 
            length = strlen(buf);
            if (buf[length - 1] != '\n') {
               if (write(fd, buf, length) != length) {
                  perror("write failed!");
                  exit(1);
               }
               continuation = 1;
               continue;
            }
  
            buf[length - 1] = '\r';
            if (write(fd, buf, length) != length) {
               perror("write failed!");
               exit(1);
            }
            buf[0]='\n';
            if (write(fd, buf, 1) != 1) {
               perror("write failed!");
               exit(1);
            }
         }
         break;
 
      case 0:  /* child */
 
         /*
          *   Read the response from the server.
          */
         while (1) {
            if ((nbytes = read(fd, buf, BUFSIZ)) <= 0) {
                 exit(0);
            }
            (void) write(0, buf, nbytes);
         }
   }
 
   exit(0);
}
 
void
handler()
{
        exit(0);
}
 
Protocols
 
Now let's look at some protocols:
 
the Hypertext Transfer Protocol (HTTP).
 
HTTP is the protocol used on the World-Wide Web.
 
First, you must make a connection to a web server.  Then, you must
send the following:
 
        Method Space Request-URI Space HTTP-Version NewLine
 
Then optionally send one or more the following header lines:
 
        From: Space mailaddress NewLine
        If-Modified-Since: Space HTTP-date NewLine
        Authorization: Space credentials NewLine
        Referer: Space Location NewLine
 
Then send the following:
 
        NewLine
 
The Method can be one of the following: GET, HEAD, or POST
The Request-URI refers to a data-producing process, and is identified by
a path name.  The HTTP-Version is a string of the form "HTTP/1.0".
 
The GET method means retrieve whatever information is identified by
the Request-URI.  For example:
 
        GET / HTTP/1.0
 
The semantics of the GET method changes to a "conditional GET" if
the request message includes an If-Modified-Since header field. A
conditional GET method requests that the identified resource be
transferred only if it has been modified since the date given by
the If-Modified-Since header. The conditional GET method is intended
to reduce network usage by allowing cached entities to be refreshed
without requiring multiple requests or transferring unnecessary data.
 
The HEAD method is identical to GET except that the server only
returns header information instead of the body of the information.
There is no "conditional HEAD" request analogous to the conditional
GET. If an If-Modified-Since header field is included with a
HEAD request, the server will ignore it.
 
The POST method is used to request that the destination server
accept information enclosed in the request.  It is generally
used post messages to bulliten boards and submitting forms.
 
The optional header lines consist of the following:
 
- The From header field, if given, must contain an Internet e-mail
  address for the human user who controls the client application.
  The address should be machine-usable.  An example is:
 
                 From: padovano@sparky.cims.nyu.edu
 
  This header field is used by the server for logging purposes
  and as a means for identifying the source of invalid requests.
 
- The If-Modified-Since header field is used with the GET method
  to make it conditional: if the requested resource has not been
  modified since the time specified in this field, a copy of the
  resource will not be returned from the server; instead,
  a 304 (described below) response will be returned without any
  entity body.
  An example of the field is:
 
                If-Modified-Since: Sat, 09 Oct 1994 19:03:31 EST
 
  The Date must be of the form:  DDD, NN MMM yyyy hh:mm:ss EST
 
  The purpose of this feature is to allow efficient updates of
  cached information with a minimum amount of transaction overhead.
 
- The Authorization field is used by a client that wishes to
  authenticate itself with a server.  This occurs usually, but
  not necessarily, after receiving a 401 response (see below).
 
- The Referer request header field allows the client to specify,
  for the server's benefit, the address of the resource from which
  the request  was obtained. This allows a server to generate
  lists of back-links to resources for interest, logging, optimized
  caching, etc. It also allows obsolete or mistyped links to be
  traced for maintenance.
 
The server responds with a Status line, optionally followed by the
requested information.  The Status-Line consists of the protocol
version followed by a numeric status code and its associated textual
phrase, with each element separated by space characters, followed
by a NewLine:
 
       HTTP-Version Space Status-Code Space Reason-Phrase NewLine
 
The server then optionally sends one or more the following header lines:
 
        Location:  full_URL_path
        WWW-Authenticate: challenge
 
It then sends the following:
 
        NewLine
 
And then it sends the Entity Body, which is a HTTP document
 
The Status-Code element is a 3-digit integer result code of the
attempt to understand and satisfy the request. The Reason-Phrase
is intended to give a short textual description of the Status-Code.
The Status-Code is intended for use by automata and the
Reason-Phrase is intended for the human user.
 
The first digit of the Status-Code defines the class of response.
The last two digits do not have any categorization role.  There
are 5 values for the first digit:
 
 1xx: Informational - Not used, but reserved for future use
 2xx: Success - The action was successfully received, understood, and accepted.
 3xx: Redirection - Further action must be taken in order to complete
      the request
 4xx: Client Error - The request contains bad syntax or cannot be fulfilled
 5xx: Server Error - The server failed to fulfill an apparently valid request
 
The 1xx class of status code indicates a provisional response, consisting
only of the Status-Line and optional headers, and is terminated by an
empty line. HTTP/1.0 does not define any 1xx status codes and they are
not a valid response to a HTTP/1.0 request.
 
The 2xx class of status code indicates that the client's request was
successfully received, understood, and accepted.   Valid values are:
 
200 OK  The request has succeeded.
 
201 Created     The request has been fulfilled and resulted in
    a new resource being created. This is usually the result of a
    POST operation.
 
202 Accepted    The request has been accepted for processing,
    but the processing has not been completed.  Its purpose is
    to allow a server to accept a request for some other process
    (perhaps a batch-oriented process that is only run once per day)
    without requiring that the user agent's connection to the server
    persist until the process is completed.
 
204 No Content  The server has fulfilled the request but there
    is no new information to send back.
 
The 3xx class of status code indicates that further action needs
to be taken by the user agent in order to fulfill the request.
The action required can sometimes be carried out by the user agent
without interaction with the user, but it is strongly recommended
that this only take place if the method used in the request is GET
or HEAD. A user agent should never automatically redirect a request
more than 5 times, since such redirections usually indicate an
infinite loop.
 
300 Multiple Choices            The requested resource is available
    at one or more locations. Unless it was a HEAD request, the
    response will include an entity containing a list of resource
    characteristics and locations from which the client can choose
    the one most appropriate.
 
301 Moved Permanently           The requested resource has been
    assigned a new permanent URL and any future references to this
    resource should be done using that URL. The new URL must be
    given by the Location field in the response. Unless it was
    a HEAD request, the Entity-Body of the response should contain
    a short note with a hyperlink to the new URL.
 
302 Moved Temporarily           The requested resource resides
    temporarily under a different URL. Since the redirection may
    be altered on occasion, the client should continue to use the
    Request-URI for future requests.
 
304 Not Modified                If the client has performed a
    conditional GET request and access is allowed, but the document
    has not been modified since the date and time specified in
    the If-Modified-Since field, the server shall respond with
    this status code and not send an Entity-Body to the client.
 
The 4xx class of status code is intended for cases in which the client
seems to have erred.
 
400 Bad Request         The request could not be understood by
    the server due to malformed syntax.
 
401 Unauthorized                The request requires user authentication.
    The response must include a WWW-Authenticate header field
    containing a challenge applicable to the requested resource.
    The client may repeat the request with a suitable Authorization
    header field. If the request already included Authorization
    credentials, then the 401 response indicates that authorization
    has been refused for those credentials.
 
403 Forbidden           The server understood the request, but
    is refusing to perform the request for an unspecified reason.
 
404 Not Found           The server has not found anything matching
    the Request-URI.
 
The 5xx response status codes beginning with the digit "5" indicate
cases in which the server is aware that it has erred or is incapable
of performing the request.
 
500 Internal Server Error               The server encountered an
    unexpected condition which prevented it from fulfilling the request.
 
501 Not Implemented             The server does not support the
    functionality required to fulfill the request.
 
502 Bad Gateway         The server received an invalid response
    from the gateway or upstream server it accessed in attempting
    to fulfill the request.
 
503 Service Unavailable         The server is currently unable to
    handle the request due to a temporary overloading or maintenance
    of the server. The implication is that this is a temporary
    condition which will be alleviated after some delay.
 
 
Now another protocol:
 
The Simple Mail Transfer Protocol
 
  The client connects to the server.  The server is listeneing on port
  25.
 
  After opening, you send the string "HELO" followed by your domain
  name.
 
  Example:  HELO  cs.nyu.edu
 
   The first step in the procedure is the MAIL command.  The
   contains the source mailbox.
 
     MAIL  FROM:
 
  Example: MAIL FROM: padovano@cs.nyu.edu
 
  This command tells the SMTP-receiver that a new mail
  transaction is starting and to reset all its state tables and
  buffers, including any recipients or mail data.  It gives the
  reverse-path which can be used to report errors.  If accepted,
  the receiver-SMTP returns a 250 OK reply.
 
  The second step in the procedure is the RCPT command.
 
     RCPT  TO:
 
  Example:  RCPT  TO: bill.clinton@whitehouse.gov
 
  This command gives a forward-path identifying one recipient.
  If accepted, the receiver-SMTP returns a 250 OK reply, and
  stores the forward-path.  If the recipient is unknown the
  receiver-SMTP returns a 550 Failure reply.  This second step of
  the procedure can be repeated any number of times.
 
  The third step in the procedure is the DATA command.
 
     DATA
 
  If accepted, the receiver-SMTP returns a 354 Intermediate reply
  and considers all succeeding lines to be the message text.
  When the end of text is received and stored the SMTP-receiver
  sends a 250 OK reply.
 
  The data is ended with a "." on a single line, and should contain
  mail headers.
 
  S: MAIL FROM: padovano@cs.nuy.edu
  R: 250 ok
  S: RCPT TO: bill.clinton@whitehouse.gov
  R: 250 ok
  S: DATA
  R: 354 send the mail data, end with .
  S: From: padovano@cs.nuy.edu
  S: To: bill.clinton@whitehouse.gov
  S: Subject: Good job
  S:
  S:   Just a quick note to say you're doing a fine job.
  S:   Keep up the good work.
  S: .
  R: 250 ok
 
  End the sessions with QUIT
 
  Example:  QUIT
 
Now let's look at an authentication protocol:
 
  - UNIX passwords are encrypted, and stored in a password file.
  - When you type in you passowrd, the login program encrypts it and
    sees if it matched what's in the file.
 
Kerberos
 
Authentication software
 
 - You only have to authenticate yourself once.
 
 - Every user has a password, and every service has a password
 
 - An "authentication server" has a list of all
   passwords (but they're encrypted)
 
 - Authentication is done with "tickets".
 
 - A special service called the "ticket granting service" gives out
   all tickets.
 
How does it work?
 
1. I walk up to a workstation and login.  I enter your login name
   in response to the login prompt.
 
2. Before I am prompted for a password, a message is sent to the
   Kerberos authentication server.
 
   The message contains:
 
               padovano, TGS
 
   Because the message only contains two names, it is not encrypted.
 
3. The authentication server looks up your name and the "TGS" name in
   a database, and obtains the encrypted passwords for each.
 
4. The authentication server creates the following message (called a ticket):
 
        "padovano, TGS, IP-address-of-padovano's-workstation, TGS-session-key"
 
   The "TGS-session-key" is a random number.
 
   The authentication server then encrypts that information with the
   encrypted password of the TGS service.  So, it looks like:
 
         "xyuxyuyycuyuywuyduwyudyxyusyxusyuyuyu"
 
   and only the TGS service can translate it back to:
 
        "padovano, TGS, IP-address-of-padovano's-workstation, TGS-session-key"
 
   The encrypted ticket is called a "sealed-ticket".
 
   The authentication server then creates the following message:
 
        "TGS-session-key, sealed-ticket"
 
   and encrypts that with padovano's encrypted password.  So, the
   messgae looks like:
 
        "jkfdjhdwjryhwjfhjkhdkjshfkjshkjfhdjhjkjk"
 
   and only the person that knows padovano's encrypted password can
   change it back to:
 
        "TGS-session-key, sealed-ticket"
 
   The encrypted message is sent back to the workstation.
 
5. The login program gets the message, and prompts me for my password.
   I enter my password, and the login program encrypts it.  It uses that
   to decrypt the message it got from the authentication server, so it
   now has:
 
        "TGS-session-key, sealed-ticket"
 
   The TGS-session-key is kept on my workstation.
 
Now let's try to use a service!  Let's say the "remote-users" service that
you wrote for homework 2.
 
 
6. The client builds a message to be sent to the ticket-granting service.
   First, it creates the following:
 
       padovano, IP-address-of-padovano's-workstation, current-time
 
   Then, it encrypts that with the TGS-session-key.  The result is called
   a "sealed-authenticator"
 
   It then sends the following to the ticket-granting service:
 
       sealed-ticket, sealed-authenticator, "remote-users-service"
 
 
7. The tcket-granting service reads the message.  It decrypts the
   sealed-ticket using its password.
 
   It now has:
 
   "padovano, TGS, IP-address-of-padovano's-workstation, TGS-session-key"
   sealed-authenticator, "remote-users-service"
 
   It then decrypts the sealed-authenticator using the TGS-session-key.
   It now has:
 
   "padovano, TGS, IP-address-of-padovano's-workstation, TGS-session-key"
   "padovano, IP-address-of-padovano's-workstation, current-time"
   "remote-users-service"
 
   It checks that the name and the IP address, and checks that the time is
   recent.  If the names match, then only the person that knew the
   TGS-session-key could have encrypted the packet.  And, the only one that
   knows the TGS-session-key is the person that know's padovano's password.
 
   The TGS then looks up the encrypted password of the remote-users-service.
 
8. The TGS forms a new, random session key and creates a new ticket:
 
     "padovano, remote-users-service, IP-address-of-padovano's-workstation,
      new-session-key"
 
   That is then encrypted using the remote-users-service encrypted password,
   creating "sealed-ticket-2".
 
   The TGS creates a new message containing:
 
       new-session-key, sealed-ticket-2
 
   That is then encrpyted using the TGS-session-key from the original message.
 
9. When my workstation gets the message, it decrpyts the message using the
   TGS-session-key is had stored.  It now has:
 
      new-session-key, sealed-ticket-2
 
10. The workstation builds another authenticator:
 
       padovano, IP-address-of-padovano's-workstation, current-time
 
   Then, it encrypts that with the new-session-key,  creating a new
   "sealed-authenticator" (let's call it sealed-authenticator-2)
 
   It then sends the following to the remote-users-service:
 
       sealed-ticket-2, sealed-authenticator-2, "remote-users-service"
 
11. The remote-users-service decrpyts the sealed-ticket-2 using its
    encrypyed password.  It now has:
 
      "padovano, remote-users-service, IP-address-of-padovano's-workstation,
       new-session-key"
      sealed-authenticator-2, "remote-users-service"
 
    It uses the new-session-key to decrypt the sealed-authenticator-2, giving
 
      "padovano, remote-users-service, IP-address-of-padovano's-workstation,
       new-session-key"
      "padovano, IP-address-of-padovano's-workstation, current-time"
      "remote-users-service"
 
    If the names and IP address match and the time is valid, then the
    sealed-authenticator-2 was encrypted properly.  And, that could only
    be done if the encryptor knew new-session-key, and that is the person that
    new the TGS-session-key.