home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / BOOTPD.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  14KB  |  508 lines

  1. /*
  2.  * Center for Information Technology Integration
  3.  *           The University of Michigan
  4.  *                    Ann Arbor
  5.  *
  6.  * Dedicated to the public domain.
  7.  * Send questions to info@citi.umich.edu
  8.  *
  9.  * BOOTP is documented in RFC 951 and RFC 1048
  10.  * Delinted, ANSIfied and reformatted - 5/30/91 P. Karn
  11.  */
  12.   
  13.   
  14. /*
  15.  * BOOTP (bootstrap protocol) server daemon.
  16.  *
  17.  */
  18.   
  19.   
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include <ctype.h>
  23. #include <time.h>
  24.   
  25. #include "global.h"
  26. #ifdef BOOTP
  27. #include "bootp.h"
  28. #include "cmdparse.h"
  29. #include "iface.h"
  30. #include "mbuf.h"
  31. #include "proc.h"
  32. #include "socket.h"
  33. #include "bootpd.h"
  34. #include "udp.h"
  35. #include "ip.h"
  36. #include "arp.h"
  37. #include "netuser.h"
  38.   
  39. void bootpd __ARGS((struct iface *iface, struct udp_cb *sock, int cnt));
  40.   
  41. struct udp_cb *Bootpd_cb = NULLUDP;
  42.   
  43. char homedir[64] = "";              /* bootfile homedirectory */
  44. char defaultboot[64] = "";          /* default file to boot */
  45.   
  46. struct host hosts[MHOSTS+1];
  47. int Nhosts = 0;      /* current number of hosts */
  48.   
  49. int32 bp_DefaultDomainNS[BP_MAXDNS] =  {0};
  50.   
  51. struct bootpd_stat Bootpd_stat;
  52.   
  53. char *ArpNames[] = {
  54.     "Netrom",
  55.     "Ethernet",
  56.     "AX25",
  57.     "Pronet",
  58.     "Chaos",
  59.     "IEEE 802",
  60.     "ArcNet",
  61.     "AppleTalk"
  62. };
  63.   
  64.   
  65. /* Routine declarations */
  66. static int bootpd_recv __ARGS((struct udp_cb *sock,struct bootp *bootp));
  67. static void sendreply __ARGS((struct bootp *bp,struct iface *iface));
  68. static void vend_fill __ARGS((char *vend,struct iface *iface,struct host *hp));
  69. static void vend_print __ARGS((char *vend));
  70. static void bootpd_request __ARGS((struct bootp *rq,struct iface *iface));
  71.   
  72. /* The bootp server. */
  73. void
  74. bootpd(iface,sock,cnt)
  75. struct iface *iface;
  76. struct udp_cb *sock;
  77. int cnt;
  78. {
  79.     struct bootp bp_packet;
  80.   
  81.     while(bootpd_recv(sock, &bp_packet) != -1) {
  82.   
  83.         if(readtab() == -1) /* maybe re-read bootptab */
  84.             return;
  85.   
  86.         switch(uchar(bp_packet.op)) {
  87.             case BOOTREQUEST:
  88.                 bootpd_request(&bp_packet, iface);
  89.                 break;
  90.             case BOOTREPLY:
  91.             /* Replies are not forwarded, left to the gateway */
  92.                 break;
  93.         }
  94.   
  95.     }
  96.   
  97. }
  98.   
  99. /* A packet has been received, read it into a bootp structure. */
  100. static int
  101. bootpd_recv(sock, bootp)
  102. struct udp_cb *sock;
  103. struct bootp *bootp;
  104. {
  105.     struct socket fsock;
  106.     struct mbuf *bp;
  107.     int len;
  108.   
  109.     /* increment the rcvd cnt */
  110.     Bootpd_stat.rcvd++;
  111.   
  112.     /* receive the packet */
  113.     len = recv_udp(sock,&fsock,&bp);
  114.     if(len == -1)
  115.         return -1;
  116.   
  117.   
  118.     /* check length of packet */
  119.     if(len < sizeof(struct bootp)) {
  120.         Bootpd_stat.bad_size++;
  121.         bootp->op = 0;
  122.         free_p(bp);
  123.         return -1;
  124.     }
  125.   
  126.     /* parse the packet */
  127.     pullup (&bp, (char *)bootp, sizeof (struct bootp));
  128.     free_p(bp);
  129.   
  130.     if(bootp->op != BOOTREPLY  &&  bootp->op != BOOTREQUEST) {
  131.         Bootpd_stat.bad_op++;
  132.         bootp->op = 0;
  133.         return -1;
  134.     }
  135.   
  136.     bootp->ciaddr.s_addr = (unsigned long) get32 ((char *)&(bootp->ciaddr));
  137.     bootp->giaddr.s_addr = (unsigned long) get32 ((char *)&(bootp->giaddr));
  138.     return 0;
  139. };
  140.   
  141.   
  142. /*
  143.  * Process BOOTREQUEST packet.
  144.  *
  145.  * (Note, this version of the bootp.c server never forwards
  146.  * the request to another server.  In our environment the
  147.  * stand-alone gateways perform that function.)
  148.  *
  149.  * (Also this version does not interpret the hostname field of
  150.  * the request packet;  it COULD do a name->address lookup and
  151.  * forward the request there.)
  152.  */
  153.   
  154. static void
  155. bootpd_request (rq, iface)
  156. struct bootp *rq;
  157. struct iface *iface;
  158. {
  159.   
  160.     struct bootp *rp;
  161.     char path[64], file[64];
  162.     struct host *hp;
  163.     int n;
  164.     time_t tloc;
  165.     int32 ipaddr;
  166.     struct arp_type *at;
  167.   
  168.     time(&tloc);
  169.     bp_log ("\nBootpd request packet received %s", ctime(&tloc));
  170.     /* Forwarding not done here. */
  171.     if(rq->giaddr.s_addr)  {
  172.         bp_log ("     Dropped, giaddr specifies to be forwarded;\n");
  173.         return;
  174.     }
  175.   
  176.     /* Is a specific host requested? */
  177.     if((strlen(rq->sname) != 0) && (strcmp (Hostname, rq->sname) != 0)) {
  178.         bp_log ("     Dropped, sname specifies server '%s'\n", rq->sname);
  179.         return;
  180.     }
  181.   
  182.     /* allocate the reply */
  183.     rp = (struct bootp *) calloc (1, sizeof (struct bootp));
  184.   
  185.     /* copy for construction */
  186.     memcpy (rp, rq, sizeof (struct bootp) - sizeof (rp->vend));
  187.   
  188.     rp->op = BOOTREPLY;
  189.   
  190.     hp = NULLHOST;
  191.   
  192.   
  193.     /* If the client doesn't know it's ip address, find one. */
  194.     if(rq->ciaddr.s_addr == 0) {
  195.   
  196.         /*
  197.          * client doesn't know his IP address,
  198.          * search by hardware address.
  199.          */
  200.         at = &Arp_type[rq->htype];
  201.         bp_log ("     Resolved by %s addr %s\n", ArpNames[rq->htype],
  202.         (*at->format)(bp_ascii, rq->chaddr));
  203.   
  204.         for(hp = &hosts[0], n = 0 ; n < Nhosts ; n++,hp++)
  205.             if((rq->htype == hp->htype)
  206.                 && (strncmp(rq->chaddr, hp->haddr, rq->hlen) == 0))
  207.                 break;
  208.   
  209.         /* If the client wasn't found, assign an IP address */
  210.         if(n == Nhosts) {
  211.   
  212.             hp = NULLHOST;
  213.             if(da_assign(iface, rq->chaddr, &ipaddr) != 0) {
  214.                 free (rp);
  215.                 bp_log ("     No dynamic addresses available.\n");
  216.                 return;
  217.             } else {
  218.                 put32 ((char *) &(rp->yiaddr), ipaddr);
  219.                 bp_log ("     Dynamic address assigned: %s\n",
  220.                 inet_ntoa (ipaddr));
  221.             }
  222.         } else {
  223.             bp_log ("     Static address assigned: %s\n",
  224.             inet_ntoa (hp->iaddr.s_addr));
  225.             put32 ((char *) &(rp->yiaddr), hp->iaddr.s_addr);
  226.         }
  227.   
  228.     } else {
  229.         /* search by IP address */
  230.         bp_log ("     Resolve by IP addr %s\n", inet_ntoa (rq->ciaddr.s_addr));
  231.         for(hp = &hosts[0], n = 0 ; n < Nhosts ; n++,hp++)
  232.             if(rq->ciaddr.s_addr == hp->iaddr.s_addr)
  233.                 break;
  234.         if(n == Nhosts) {
  235.             hp = NULLHOST;
  236.             bp_log ("     Host not found, default values used.\n");
  237.         } else
  238.             bp_log ("     Lookup successful.\n");
  239.         put32 ((char *) &(rp->ciaddr), rq->ciaddr.s_addr);
  240.     }
  241.   
  242.     put32 ((char *) &(rp->siaddr), iface->addr);
  243.   
  244.     /* Determine the bootp file */
  245.     file[0] = 0;
  246.     if(rq->file[0] == 0) {      /* if client didn't specify file */
  247.         /* Use the host record file, else the default file */
  248.         if((hp == NULLHOST) || (hp->bootfile[0] == 0))
  249.             strcpy(file, defaultboot);
  250.         else
  251.             strcpy(file, hp->bootfile);
  252.     } else {
  253.         /* use client specified file */
  254.         strcpy(file, rq->file);
  255.     }
  256.   
  257.     /* If a file is specified, specify the path to the bootp file */
  258.     path[0] = 0;
  259.     if((*homedir != 0) && (*file != 0)) {
  260.         strcpy(path, homedir);
  261.         strcat(path, "/");
  262.     }
  263.   
  264.     if(file[0] == '/')     /* if absolute pathname */
  265.         strcpy(path, file);
  266.     else
  267.         strcat(path, file);
  268.   
  269.     /* No files are provided here, just return a path. */
  270.     strcpy(rp->file, path);
  271.   
  272.     /* Fill in the vendor information */
  273.     vend_fill (rp->vend, iface, hp);
  274.   
  275.     sendreply (rp, iface);
  276.     free (rp);
  277.   
  278. };
  279.   
  280.   
  281. /* Print the bootp structure. */
  282. void
  283. bootp_print_packet  (bp)
  284. struct bootp *bp;
  285. {
  286.     bp_log ("Packet op code........................%d\n", bp->op);
  287.     bp_log ("hardware address type.................%d\n", bp->htype);
  288.     bp_log ("hardware address length...............%d\n", bp->hlen);
  289.     bp_log ("client sets to zero...................%d\n", bp->hops);
  290.     bp_log ("transaction ID........................%ld\n", bp->xid);
  291.     bp_log ("seconds elapsed since client booted...%d\n", bp->secs);
  292.     bp_log ("unused................................%d\n", bp->unused);
  293.     bp_log ("Client IP address, if known...........%s\n",
  294.     inet_ntoa ((int32)bp->ciaddr.s_addr));
  295.     bp_log ("Server supplied IP address............%s\n",
  296.     inet_ntoa ((int32)bp->yiaddr.s_addr));
  297.     bp_log ("Server IP address.....................%s\n",
  298.     inet_ntoa ((int32)bp->siaddr.s_addr));
  299.     bp_log ("Gateway IP address....................%s\n",
  300.     inet_ntoa ((int32)bp->giaddr.s_addr));
  301.     bp_log ("Client hardware address...............%x:%x:%x:%x:%x:%x\n",
  302.     bp->chaddr[0], bp->chaddr[1], bp->chaddr[2],
  303.     bp->chaddr[3], bp->chaddr[4], bp->chaddr[5]);
  304.     bp_log ("Server host name......................'%s'\n", bp->sname);
  305.     bp_log ("Boot file name........................'%s'\n", bp->file);
  306.   
  307.     vend_print (bp->vend);
  308. }
  309.   
  310.   
  311.   
  312. static void
  313. vend_print (vend)
  314. char *vend;
  315. {
  316.     unsigned char ch;
  317.     int size;
  318.     char *start;
  319.     int32 *ipaddr;
  320.     int i;
  321.   
  322.     start = vend;
  323.   
  324.     bp_log ("Magic Cookie..........................x%02x%02x%02x%02x\n",
  325.     (int) vend[0], (int) vend[1], (int) vend[2], (int) vend[3]);
  326.     vend = vend + 4;
  327.   
  328.     while(((ch = *vend++) != BOOTP_END) && (vend - start <= 64))
  329.     switch(ch) {
  330.   
  331.         case BOOTP_PAD:  /* They're just padding */
  332.             continue;
  333.         case BOOTP_SUBNET:      /* fixed length, 4 octets */
  334.             size = (int) *vend++;
  335.             ipaddr = (int32 *) vend;
  336.             bp_log ("Vend Subnet...........................%s\n", inet_ntoa
  337.             (*ipaddr));
  338.             vend += size;
  339.             break;
  340.         case BOOTP_HOSTNAME:
  341.             size = (int) *vend++;
  342.             bp_log ("Vend Hostname.........................%s\n", vend);
  343.             vend += size;
  344.             break;
  345.         case BOOTP_DNS:
  346.             size = (int) *vend++;
  347.             for(i = 0; i < (size / 4); i++) {
  348.                 ipaddr = (int32 *) vend;
  349.                 bp_log ("Vend DomainNS.........................%s\n",
  350.                 inet_ntoa (*ipaddr));
  351.                 vend += 4;
  352.             }
  353.             break;
  354.         case BOOTP_GATEWAY:
  355.             size = (int) *vend++;
  356.             for(i = 0; i < (size / 4); i++) {
  357.                 ipaddr = (int32 *) vend;
  358.                 bp_log ("Vend Gateway..........................%s\n",
  359.                 inet_ntoa (*ipaddr));
  360.                 vend += 4;
  361.             }
  362.             break;
  363.   
  364.   
  365.         default:        /* variable field we don't know about */
  366.             size = *vend++;
  367.             vend += size;
  368.             break;
  369.     }
  370.   
  371. }
  372.   
  373.   
  374. static char cookie[5] = {99, 130, 83, 99, 0};
  375.   
  376. static void
  377. vend_fill (vend, iface, hp)
  378. char *vend;
  379. struct iface *iface;
  380. struct host *hp;
  381. {
  382.     int     len;
  383.     int mod;
  384.     int i;
  385.     char    *sizep;
  386.   
  387.     /* Magic cookie */
  388.     strcpy (vend, cookie);
  389.     vend += 4;
  390.   
  391.     /* Send the iface subnet */
  392.     /* Pad so number falls on word boundry */
  393.   
  394.     vend++;
  395.     vend++;
  396.   
  397.     *vend = BOOTP_SUBNET;
  398.     vend++;
  399.     *vend = 4;
  400.     vend++;
  401.     put32 (vend, iface->netmask);
  402.     vend += 4;
  403.   
  404.   
  405.     /* Send the DNS */
  406.     if(bp_DefaultDomainNS[0] != 0) {
  407.         /* Pad for allignment */
  408.         vend++;
  409.         vend++;
  410.   
  411.         *vend = BOOTP_DNS;
  412.         vend++;
  413.         sizep = vend;
  414.         vend++;
  415.         for(i = 0; (i < BP_MAXDNS) && (bp_DefaultDomainNS[i] != 0); i++) {
  416.             put32 (vend, bp_DefaultDomainNS[i]);
  417.             *sizep = *sizep + 4;
  418.             vend += 4;
  419.         }
  420.     }
  421.   
  422.     /* Send the default gateway */
  423.     if(R_default.iface == iface) {
  424.         vend++;
  425.         vend++;
  426.   
  427.         *vend = BOOTP_GATEWAY;
  428.         vend++;
  429.         *vend = 4;
  430.         vend++;
  431.         put32 (vend, R_default.gateway);
  432.         vend +=  4;
  433.     }
  434.   
  435.     /* Send the hostname */
  436.     if(hp != NULLHOST) {
  437.         /* Pad so name begins on a word boundry */
  438.         vend++;
  439.         vend++;
  440.   
  441.         *vend = BOOTP_HOSTNAME;
  442.         vend++;
  443.         *vend = len = strlen (hp->name) + 1;
  444.         vend++;
  445.         strcpy (vend, hp->name);
  446.         vend += len;
  447.   
  448.         /* Pad to a word. */
  449.         mod = 4 - (len % 4);
  450.         for(i = 0; i < mod; i++) {
  451.             *vend = BOOTP_PAD;
  452.             vend++;
  453.         }
  454.     }
  455.   
  456.     /* Mark the end of the data */
  457.     *vend = BOOTP_END;
  458. }
  459.   
  460.   
  461.   
  462. /*
  463.  * Send a reply packet to the client.  'forward' flag is set if we are
  464.  * not the originator of this reply packet.
  465.  */
  466. static void
  467. sendreply(bp, iface)
  468. struct bootp *bp;
  469. struct iface *iface;
  470. {
  471.     struct mbuf *buf;
  472.     int32 faddr;
  473.     int16 length;
  474.     char *cp;
  475.   
  476.     /*
  477.      * If the client IP address is specified, use that
  478.      * else if gateway IP address is specified, use that
  479.      * else make a temporary arp cache entry for the client's NEW
  480.      * IP/hardware address and use that.
  481.      */
  482.     if(bp->ciaddr.s_addr) {
  483.         faddr = get32 ((char *) &(bp->ciaddr));
  484.     } else {
  485.         faddr = get32 ((char *) &(bp->yiaddr));
  486.         arp_add (faddr, (int16) bp->htype, bp->chaddr, 0, iface);
  487.     }
  488.   
  489.     if((buf = qdata ((char *)bp, sizeof (struct bootp))) == NULLBUF)
  490.         return;
  491.     if((buf = pushdown (buf, UDPHDR)) == NULLBUF)
  492.         return;
  493.   
  494.     length = sizeof (struct bootp) + UDPHDR;
  495.   
  496.     cp = buf->data;
  497.     cp = put16 (cp, IPPORT_BOOTPS);     /* Source */
  498.     cp = put16 (cp, IPPORT_BOOTPC);     /* Dest */
  499.     cp = put16 (cp, length);
  500.     *cp++ = 0;
  501.     *cp = 0;
  502.   
  503.     ip_send (iface->addr, faddr, UDP_PTCL, 0, 0, buf, length, 0, 0);
  504. };
  505.   
  506. #endif /* BOOTP */
  507.   
  508.