home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / inetutil.1 / inetutil / inetutils-1.1 / tftpd / tftpd.c < prev   
Encoding:
C/C++ Source or Header  |  1996-07-22  |  15.5 KB  |  661 lines

  1. /*
  2.  * Copyright (c) 1983, 1993
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char copyright[] =
  36. "@(#) Copyright (c) 1983, 1993\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)tftpd.c    8.1 (Berkeley) 6/4/93";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * Trivial file transfer protocol server.
  46.  *
  47.  * This version includes many modifications by Jim Guyton
  48.  * <guyton@rand-unix>.
  49.  */
  50.  
  51. #ifdef HAVE_CONFIG_H
  52. #include <config.h>
  53. #endif
  54.  
  55. #include <sys/param.h>
  56. #include <sys/ioctl.h>
  57. #include <sys/stat.h>
  58. #include <sys/socket.h>
  59.  
  60. #include <netinet/in.h>
  61. #include <arpa/tftp.h>
  62. #include <arpa/inet.h>
  63.  
  64. #include <ctype.h>
  65. #include <errno.h>
  66. #include <fcntl.h>
  67. #include <netdb.h>
  68. #include <setjmp.h>
  69. #include <signal.h>
  70. #include <stdio.h>
  71. #include <stdlib.h>
  72. #include <string.h>
  73. #include <syslog.h>
  74. #include <unistd.h>
  75.  
  76. #include "tftpsubs.h"
  77.  
  78. #define    TIMEOUT        5
  79.  
  80. int    peer;
  81. int    rexmtval = TIMEOUT;
  82. int    maxtimeout = 5*TIMEOUT;
  83.  
  84. #define    PKTSIZE    SEGSIZE+4
  85. char    buf[PKTSIZE];
  86. char    ackbuf[PKTSIZE];
  87. struct    sockaddr_in from;
  88. int    fromlen;
  89.  
  90. void    tftp __P((struct tftphdr *, int));
  91.  
  92. /*
  93.  * Null-terminated directory prefix list for absolute pathname requests and
  94.  * search list for relative pathname requests.
  95.  *
  96.  * MAXDIRS should be at least as large as the number of arguments that
  97.  * inetd allows (currently 20).
  98.  */
  99. #define MAXDIRS    20
  100. static struct dirlist {
  101.     char    *name;
  102.     int    len;
  103. } dirs[MAXDIRS+1];
  104. static int    suppress_naks;
  105. static int    logging;
  106.  
  107. static char *errtomsg __P((int));
  108. static void  nak __P((int));
  109. static char *verifyhost __P((struct sockaddr_in *));
  110.  
  111. int
  112. main(argc, argv)
  113.     int argc;
  114.     char *argv[];
  115. {
  116.     register struct tftphdr *tp;
  117.     register int n;
  118.     int ch, on;
  119.     struct sockaddr_in sin;
  120.  
  121.     openlog("tftpd", LOG_PID, LOG_FTP);
  122.     while ((ch = getopt(argc, argv, "ln")) != EOF) {
  123.         switch (ch) {
  124.         case 'l':
  125.             logging = 1;
  126.             break;
  127.         case 'n':
  128.             suppress_naks = 1;
  129.             break;
  130.         default:
  131.             syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
  132.         }
  133.     }
  134.     if (optind < argc) {
  135.         struct dirlist *dirp;
  136.  
  137.         /* Get list of directory prefixes. Skip relative pathnames. */
  138.         for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
  139.              optind++) {
  140.             if (argv[optind][0] == '/') {
  141.                 dirp->name = argv[optind];
  142.                 dirp->len  = strlen(dirp->name);
  143.                 dirp++;
  144.             }
  145.         }
  146.     }
  147.  
  148.     on = 1;
  149.     if (ioctl(0, FIONBIO, &on) < 0) {
  150.         syslog(LOG_ERR, "ioctl(FIONBIO): %m\n");
  151.         exit(1);
  152.     }
  153.     fromlen = sizeof (from);
  154.     n = recvfrom(0, buf, sizeof (buf), 0,
  155.         (struct sockaddr *)&from, &fromlen);
  156.     if (n < 0) {
  157.         syslog(LOG_ERR, "recvfrom: %m\n");
  158.         exit(1);
  159.     }
  160.     /*
  161.      * Now that we have read the message out of the UDP
  162.      * socket, we fork and exit.  Thus, inetd will go back
  163.      * to listening to the tftp port, and the next request
  164.      * to come in will start up a new instance of tftpd.
  165.      *
  166.      * We do this so that inetd can run tftpd in "wait" mode.
  167.      * The problem with tftpd running in "nowait" mode is that
  168.      * inetd may get one or more successful "selects" on the
  169.      * tftp port before we do our receive, so more than one
  170.      * instance of tftpd may be started up.  Worse, if tftpd
  171.      * break before doing the above "recvfrom", inetd would
  172.      * spawn endless instances, clogging the system.
  173.      */
  174.     {
  175.         int pid;
  176.         int i, j;
  177.  
  178.         for (i = 1; i < 20; i++) {
  179.             pid = fork();
  180.             if (pid < 0) {
  181.                 sleep(i);
  182.                 /*
  183.                  * flush out to most recently sent request.
  184.                  *
  185.                  * This may drop some request, but those
  186.                  * will be resent by the clients when
  187.                  * they timeout.  The positive effect of
  188.                  * this flush is to (try to) prevent more
  189.                  * than one tftpd being started up to service
  190.                  * a single request from a single client.
  191.                  */
  192.                 j = sizeof from;
  193.                 i = recvfrom(0, buf, sizeof (buf), 0,
  194.                     (struct sockaddr *)&from, &j);
  195.                 if (i > 0) {
  196.                     n = i;
  197.                     fromlen = j;
  198.                 }
  199.             } else {
  200.                 break;
  201.             }
  202.         }
  203.         if (pid < 0) {
  204.             syslog(LOG_ERR, "fork: %m\n");
  205.             exit(1);
  206.         } else if (pid != 0) {
  207.             exit(0);
  208.         }
  209.     }
  210.     from.sin_family = AF_INET;
  211.     alarm(0);
  212.     close(0);
  213.     close(1);
  214.     peer = socket(AF_INET, SOCK_DGRAM, 0);
  215.     if (peer < 0) {
  216.         syslog(LOG_ERR, "socket: %m\n");
  217.         exit(1);
  218.     }
  219.     memset(&sin, 0, sizeof(sin));
  220.     sin.sin_family = AF_INET;
  221.     if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
  222.         syslog(LOG_ERR, "bind: %m\n");
  223.         exit(1);
  224.     }
  225.     if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
  226.         syslog(LOG_ERR, "connect: %m\n");
  227.         exit(1);
  228.     }
  229.     tp = (struct tftphdr *)buf;
  230.     tp->th_opcode = ntohs(tp->th_opcode);
  231.     if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
  232.         tftp(tp, n);
  233.     exit(1);
  234. }
  235.  
  236. struct formats;
  237. int    validate_access __P((char **, int));
  238. void    sendfile __P((struct formats *));
  239. void    recvfile __P((struct formats *));
  240.  
  241. struct formats {
  242.     char    *f_mode;
  243.     int    (*f_validate) __P((char **, int));
  244.     void    (*f_send) __P((struct formats *));
  245.     void    (*f_recv) __P((struct formats *));
  246.     int    f_convert;
  247. } formats[] = {
  248.     { "netascii",    validate_access,    sendfile,    recvfile, 1 },
  249.     { "octet",    validate_access,    sendfile,    recvfile, 0 },
  250. #ifdef notdef
  251.     { "mail",    validate_user,        sendmail,    recvmail, 1 },
  252. #endif
  253.     { 0 }
  254. };
  255.  
  256. /*
  257.  * Handle initial connection protocol.
  258.  */
  259. void
  260. tftp(tp, size)
  261.     struct tftphdr *tp;
  262.     int size;
  263. {
  264.     register char *cp;
  265.     int first = 1, ecode;
  266.     register struct formats *pf;
  267.     char *filename, *mode;
  268.  
  269.     filename = cp = tp->th_stuff;
  270. again:
  271.     while (cp < buf + size) {
  272.         if (*cp == '\0')
  273.             break;
  274.         cp++;
  275.     }
  276.     if (*cp != '\0') {
  277.         nak(EBADOP);
  278.         exit(1);
  279.     }
  280.     if (first) {
  281.         mode = ++cp;
  282.         first = 0;
  283.         goto again;
  284.     }
  285.     for (cp = mode; *cp; cp++)
  286.         if (isupper(*cp))
  287.             *cp = tolower(*cp);
  288.     for (pf = formats; pf->f_mode; pf++)
  289.         if (strcmp(pf->f_mode, mode) == 0)
  290.             break;
  291.     if (pf->f_mode == 0) {
  292.         nak(EBADOP);
  293.         exit(1);
  294.     }
  295.     ecode = (*pf->f_validate)(&filename, tp->th_opcode);
  296.     if (logging) {
  297.         syslog(LOG_INFO, "%s: %s request for %s: %s",
  298.             verifyhost(&from),
  299.             tp->th_opcode == WRQ ? "write" : "read",
  300.             filename, errtomsg(ecode));
  301.     }
  302.     if (ecode) {
  303.         /*
  304.          * Avoid storms of naks to a RRQ broadcast for a relative
  305.          * bootfile pathname from a diskless Sun.
  306.          */
  307.         if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
  308.             exit(0);
  309.         nak(ecode);
  310.         exit(1);
  311.     }
  312.     if (tp->th_opcode == WRQ)
  313.         (*pf->f_recv)(pf);
  314.     else
  315.         (*pf->f_send)(pf);
  316.     exit(0);
  317. }
  318.  
  319.  
  320. FILE *file;
  321.  
  322. /*
  323.  * Validate file access.  Since we
  324.  * have no uid or gid, for now require
  325.  * file to exist and be publicly
  326.  * readable/writable.
  327.  * If we were invoked with arguments
  328.  * from inetd then the file must also be
  329.  * in one of the given directory prefixes.
  330.  * Note also, full path name must be
  331.  * given as we have no login directory.
  332.  */
  333. int
  334. validate_access(filep, mode)
  335.     char **filep;
  336.     int mode;
  337. {
  338.     struct stat stbuf;
  339.     int    fd;
  340.     struct dirlist *dirp;
  341.     static char *pathname = 0;
  342.     char *filename = *filep;
  343.  
  344.     /*
  345.      * Prevent tricksters from getting around the directory restrictions
  346.      */
  347.     if (strstr(filename, "/../"))
  348.         return (EACCESS);
  349.  
  350.     if (*filename == '/') {
  351.         /*
  352.          * Allow the request if it's in one of the approved locations.
  353.          * Special case: check the null prefix ("/") by looking
  354.          * for length = 1 and relying on the arg. processing that
  355.          * it's a /.
  356.          */
  357.         for (dirp = dirs; dirp->name != NULL; dirp++) {
  358.             if (dirp->len == 1 ||
  359.                 (!strncmp(filename, dirp->name, dirp->len) &&
  360.                  filename[dirp->len] == '/'))
  361.                     break;
  362.         }
  363.         /* If directory list is empty, allow access to any file */
  364.         if (dirp->name == NULL && dirp != dirs)
  365.             return (EACCESS);
  366.         if (stat(filename, &stbuf) < 0)
  367.             return (errno == ENOENT ? ENOTFOUND : EACCESS);
  368.         if ((stbuf.st_mode & S_IFMT) != S_IFREG)
  369.             return (ENOTFOUND);
  370.         if (mode == RRQ) {
  371.             if ((stbuf.st_mode & S_IROTH) == 0)
  372.                 return (EACCESS);
  373.         } else {
  374.             if ((stbuf.st_mode & S_IWOTH) == 0)
  375.                 return (EACCESS);
  376.         }
  377.     } else {
  378.         int err;
  379.  
  380.         /*
  381.          * Relative file name: search the approved locations for it.
  382.          * Don't allow write requests or ones that avoid directory
  383.          * restrictions.
  384.          */
  385.  
  386.         if (mode != RRQ || !strncmp(filename, "../", 3))
  387.             return (EACCESS);
  388.  
  389.         /*
  390.          * If the file exists in one of the directories and isn't
  391.          * readable, continue looking. However, change the error code
  392.          * to give an indication that the file exists.
  393.          */
  394.         err = ENOTFOUND;
  395.         for (dirp = dirs; dirp->name != NULL; dirp++) {
  396.             if (pathname)
  397.                 free (pathname);
  398.             pathname = malloc (strlen (dirp->name)
  399.                        + 1 + strlen (filename) + 1);
  400.             if (! pathname)
  401.                 return ENOMEM;
  402.             sprintf(pathname, "%s/%s", dirp->name, filename);
  403.             if (stat(pathname, &stbuf) == 0 &&
  404.                 (stbuf.st_mode & S_IFMT) == S_IFREG) {
  405.                 if ((stbuf.st_mode & S_IROTH) != 0) {
  406.                     break;
  407.                 }
  408.                 err = EACCESS;
  409.             }
  410.         }
  411.         if (dirp->name == NULL)
  412.             return (err);
  413.         *filep = filename = pathname;
  414.     }
  415.     fd = open(filename, mode == RRQ ? 0 : 1);
  416.     if (fd < 0)
  417.         return (errno + 100);
  418.     file = fdopen(fd, (mode == RRQ)? "r":"w");
  419.     if (file == NULL) {
  420.         return errno+100;
  421.     }
  422.     return (0);
  423. }
  424.  
  425. int    timeout;
  426. jmp_buf    timeoutbuf;
  427.  
  428. void
  429. timer()
  430. {
  431.  
  432.     timeout += rexmtval;
  433.     if (timeout >= maxtimeout)
  434.         exit(1);
  435.     longjmp(timeoutbuf, 1);
  436. }
  437.  
  438. /*
  439.  * Send the requested file.
  440.  */
  441. void
  442. sendfile(pf)
  443.     struct formats *pf;
  444. {
  445.     struct tftphdr *dp, *r_init();
  446.     register struct tftphdr *ap;    /* ack packet */
  447.     register int size, n;
  448.     volatile int block;
  449.  
  450.     signal(SIGALRM, timer);
  451.     dp = r_init();
  452.     ap = (struct tftphdr *)ackbuf;
  453.     block = 1;
  454.     do {
  455.         size = readit(file, &dp, pf->f_convert);
  456.         if (size < 0) {
  457.             nak(errno + 100);
  458.             goto abort;
  459.         }
  460.         dp->th_opcode = htons((u_short)DATA);
  461.         dp->th_block = htons((u_short)block);
  462.         timeout = 0;
  463.         (void)setjmp(timeoutbuf);
  464.  
  465. send_data:
  466.         if (send(peer, dp, size + 4, 0) != size + 4) {
  467.             syslog(LOG_ERR, "tftpd: write: %m\n");
  468.             goto abort;
  469.         }
  470.         read_ahead(file, pf->f_convert);
  471.         for ( ; ; ) {
  472.             alarm(rexmtval);        /* read the ack */
  473.             n = recv(peer, ackbuf, sizeof (ackbuf), 0);
  474.             alarm(0);
  475.             if (n < 0) {
  476.                 syslog(LOG_ERR, "tftpd: read: %m\n");
  477.                 goto abort;
  478.             }
  479.             ap->th_opcode = ntohs((u_short)ap->th_opcode);
  480.             ap->th_block = ntohs((u_short)ap->th_block);
  481.  
  482.             if (ap->th_opcode == ERROR)
  483.                 goto abort;
  484.  
  485.             if (ap->th_opcode == ACK) {
  486.                 if (ap->th_block == block)
  487.                     break;
  488.                 /* Re-synchronize with the other side */
  489.                 (void) synchnet(peer);
  490.                 if (ap->th_block == (block -1))
  491.                     goto send_data;
  492.             }
  493.  
  494.         }
  495.         block++;
  496.     } while (size == SEGSIZE);
  497. abort:
  498.     (void) fclose(file);
  499. }
  500.  
  501. void
  502. justquit()
  503. {
  504.     exit(0);
  505. }
  506.  
  507.  
  508. /*
  509.  * Receive a file.
  510.  */
  511. void
  512. recvfile(pf)
  513.     struct formats *pf;
  514. {
  515.     struct tftphdr *dp, *w_init();
  516.     register struct tftphdr *ap;    /* ack buffer */
  517.     register int n, size;
  518.     volatile int block;
  519.  
  520.     signal(SIGALRM, timer);
  521.     dp = w_init();
  522.     ap = (struct tftphdr *)ackbuf;
  523.     block = 0;
  524.     do {
  525.         timeout = 0;
  526.         ap->th_opcode = htons((u_short)ACK);
  527.         ap->th_block = htons((u_short)block);
  528.         block++;
  529.         (void) setjmp(timeoutbuf);
  530. send_ack:
  531.         if (send(peer, ackbuf, 4, 0) != 4) {
  532.             syslog(LOG_ERR, "tftpd: write: %m\n");
  533.             goto abort;
  534.         }
  535.         write_behind(file, pf->f_convert);
  536.         for ( ; ; ) {
  537.             alarm(rexmtval);
  538.             n = recv(peer, dp, PKTSIZE, 0);
  539.             alarm(0);
  540.             if (n < 0) {            /* really? */
  541.                 syslog(LOG_ERR, "tftpd: read: %m\n");
  542.                 goto abort;
  543.             }
  544.             dp->th_opcode = ntohs((u_short)dp->th_opcode);
  545.             dp->th_block = ntohs((u_short)dp->th_block);
  546.             if (dp->th_opcode == ERROR)
  547.                 goto abort;
  548.             if (dp->th_opcode == DATA) {
  549.                 if (dp->th_block == block) {
  550.                     break;   /* normal */
  551.                 }
  552.                 /* Re-synchronize with the other side */
  553.                 (void) synchnet(peer);
  554.                 if (dp->th_block == (block-1))
  555.                     goto send_ack;          /* rexmit */
  556.             }
  557.         }
  558.         /*  size = write(file, dp->th_data, n - 4); */
  559.         size = writeit(file, &dp, n - 4, pf->f_convert);
  560.         if (size != (n-4)) {                    /* ahem */
  561.             if (size < 0) nak(errno + 100);
  562.             else nak(ENOSPACE);
  563.             goto abort;
  564.         }
  565.     } while (size == SEGSIZE);
  566.     write_behind(file, pf->f_convert);
  567.     (void) fclose(file);            /* close data file */
  568.  
  569.     ap->th_opcode = htons((u_short)ACK);    /* send the "final" ack */
  570.     ap->th_block = htons((u_short)(block));
  571.     (void) send(peer, ackbuf, 4, 0);
  572.  
  573.     signal(SIGALRM, justquit);      /* just quit on timeout */
  574.     alarm(rexmtval);
  575.     n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
  576.     alarm(0);
  577.     if (n >= 4 &&                   /* if read some data */
  578.         dp->th_opcode == DATA &&    /* and got a data block */
  579.         block == dp->th_block) {    /* then my last ack was lost */
  580.         (void) send(peer, ackbuf, 4, 0);     /* resend final ack */
  581.     }
  582. abort:
  583.     return;
  584. }
  585.  
  586. struct errmsg {
  587.     int    e_code;
  588.     char    *e_msg;
  589. } errmsgs[] = {
  590.     { EUNDEF,    "Undefined error code" },
  591.     { ENOTFOUND,    "File not found" },
  592.     { EACCESS,    "Access violation" },
  593.     { ENOSPACE,    "Disk full or allocation exceeded" },
  594.     { EBADOP,    "Illegal TFTP operation" },
  595.     { EBADID,    "Unknown transfer ID" },
  596.     { EEXISTS,    "File already exists" },
  597.     { ENOUSER,    "No such user" },
  598.     { -1,        0 }
  599. };
  600.  
  601. static char *
  602. errtomsg(error)
  603.     int error;
  604. {
  605.     static char buf[20];
  606.     register struct errmsg *pe;
  607.     if (error == 0)
  608.         return "success";
  609.     for (pe = errmsgs; pe->e_code >= 0; pe++)
  610.         if (pe->e_code == error)
  611.             return pe->e_msg;
  612.     sprintf(buf, "error %d", error);
  613.     return buf;
  614. }
  615.  
  616. /*
  617.  * Send a nak packet (error message).
  618.  * Error code passed in is one of the
  619.  * standard TFTP codes, or a UNIX errno
  620.  * offset by 100.
  621.  */
  622. static void
  623. nak(error)
  624.     int error;
  625. {
  626.     register struct tftphdr *tp;
  627.     int length;
  628.     register struct errmsg *pe;
  629.  
  630.     tp = (struct tftphdr *)buf;
  631.     tp->th_opcode = htons((u_short)ERROR);
  632.     tp->th_code = htons((u_short)error);
  633.     for (pe = errmsgs; pe->e_code >= 0; pe++)
  634.         if (pe->e_code == error)
  635.             break;
  636.     if (pe->e_code < 0) {
  637.         pe->e_msg = strerror(error - 100);
  638.         tp->th_code = EUNDEF;   /* set 'undef' errorcode */
  639.     }
  640.     strcpy(tp->th_msg, pe->e_msg);
  641.     length = strlen(pe->e_msg);
  642.     tp->th_msg[length] = '\0';
  643.     length += 5;
  644.     if (send(peer, buf, length, 0) != length)
  645.         syslog(LOG_ERR, "nak: %m\n");
  646. }
  647.  
  648. static char *
  649. verifyhost(fromp)
  650.     struct sockaddr_in *fromp;
  651. {
  652.     struct hostent *hp;
  653.  
  654.     hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (fromp->sin_addr),
  655.                 fromp->sin_family);
  656.     if (hp)
  657.         return hp->h_name;
  658.     else
  659.         return inet_ntoa(fromp->sin_addr);
  660. }
  661.