home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / bootpd-2.zip / BOOTPTES.C < prev    next >
C/C++ Source or Header  |  1995-09-04  |  12KB  |  525 lines

  1. /*
  2.  * bootptest.c - Test out a bootp server.
  3.  *
  4.  * This simple program was put together from pieces taken from
  5.  * various places, including the CMU BOOTP client and server.
  6.  * The packet printing routine is from the Berkeley "tcpdump"
  7.  * program with some enhancements I added.  The print-bootp.c
  8.  * file was shared with my copy of "tcpdump" and therefore uses
  9.  * some unusual utility routines that would normally be provided
  10.  * by various parts of the tcpdump program.  Gordon W. Ross
  11.  *
  12.  * Boilerplate:
  13.  *
  14.  * This program includes software developed by the University of
  15.  * California, Lawrence Berkeley Laboratory and its contributors.
  16.  * (See the copyright notice in print-bootp.c)
  17.  *
  18.  * The remainder of this program is public domain.  You may do
  19.  * whatever you like with it except claim that you wrote it.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  22.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  23.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  *
  25.  * HISTORY:
  26.  *
  27.  * 12/02/93 Released version 1.4 (with bootp-2.3.2)
  28.  * 11/05/93 Released version 1.3
  29.  * 10/14/93 Released version 1.2
  30.  * 10/11/93 Released version 1.1
  31.  * 09/28/93 Released version 1.0
  32.  * 09/93 Original developed by Gordon W. Ross <gwr@mc.com>
  33.  */
  34.  
  35. char *usage = "bootptest [-h] server-name [vendor-data-template-file]";
  36.  
  37. #include <sys/types.h>
  38. #include <sys/socket.h>
  39. #include <sys/ioctl.h>
  40. #include <sys/file.h>
  41. #include <sys/time.h>
  42. #include <sys/stat.h>
  43. #include <sys/utsname.h>
  44.  
  45. #include <net/if.h>
  46. #include <netinet/in.h>
  47. #include <arpa/inet.h>            /* inet_ntoa */
  48.  
  49. #ifndef    NO_UNISTD
  50. #include <unistd.h>
  51. #endif
  52.  
  53. #ifndef    NO_UNISTD
  54. #include <unistd.h>
  55. #endif
  56. #include <stdlib.h>
  57. #include <signal.h>
  58. #include <stdio.h>
  59. #include <string.h>
  60. #include <errno.h>
  61. #include <ctype.h>
  62. #include <netdb.h>
  63. #include <assert.h>
  64.  
  65. #include "bootp.h"
  66. #include "bootptest.h"
  67. #include "getif.h"
  68. #include "getether.h"
  69.  
  70. #include "patchlevel.h"
  71.  
  72. static void send_request();
  73.  
  74. extern int getether();
  75. static void send_request();
  76.  
  77. #define LOG_ERR 1
  78. #define BUFLEN 1024
  79. #define WAITSECS 1
  80. #define MAXWAIT  10
  81.  
  82. int vflag = 1;
  83. int tflag = 0;
  84. int thiszone;
  85. char *progname;
  86. unsigned char *packetp;
  87. unsigned char *snapend;
  88. int snaplen;
  89.  
  90.  
  91. /*
  92.  * IP port numbers for client and server obtained from /etc/services
  93.  */
  94.  
  95. u_short bootps_port, bootpc_port;
  96.  
  97.  
  98. /*
  99.  * Internet socket and interface config structures
  100.  */
  101.  
  102. struct sockaddr_in sin_server;    /* where to send requests */
  103. struct sockaddr_in sin_client;    /* for bind and listen */
  104. struct sockaddr_in sin_from;    /* Packet source */
  105. u_char eaddr[16];                /* Ethernet address */
  106.  
  107. /*
  108.  * General
  109.  */
  110.  
  111. int debug = 1;                    /* Debugging flag (level) */
  112. char *sndbuf;                    /* Send packet buffer */
  113. char *rcvbuf;                    /* Receive packet buffer */
  114.  
  115. struct utsname my_uname;
  116. char *hostname;
  117.  
  118. /*
  119.  * Vendor magic cookies for CMU and RFC1048
  120.  */
  121.  
  122. unsigned char vm_cmu[4] = VM_CMU;
  123. unsigned char vm_rfc1048[4] = VM_RFC1048;
  124. short secs;                        /* How long client has waited */
  125.  
  126. char *get_errmsg();
  127. extern void bootp_print();
  128.  
  129. /*
  130.  * Initialization such as command-line processing is done, then
  131.  * the receiver loop is started.  Die when interrupted.
  132.  */
  133.  
  134. void
  135. main(argc, argv)
  136.     int argc;
  137.     char **argv;
  138. {
  139.     struct bootp *bp;
  140.     struct servent *sep;
  141.     struct hostent *hep;
  142.  
  143.     char *servername = NULL;
  144.     char *vendor_file = NULL;
  145.     char *bp_file = NULL;
  146.     int32 server_addr;            /* inet addr, network order */
  147.     int s;                        /* Socket file descriptor */
  148.     int n, fromlen, recvcnt;
  149.     int use_hwa = 0;
  150.     int32 vend_magic;
  151.     int32 xid;
  152.  
  153.     progname = strrchr(argv[0], '/');
  154.     if (progname)
  155.         progname++;
  156.     else
  157.         progname = argv[0];
  158.     argc--;
  159.     argv++;
  160.  
  161.     if (debug)
  162.         printf("%s: version %s.%d\n", progname, VERSION, PATCHLEVEL);
  163.  
  164.     /*
  165.      * Verify that "struct bootp" has the correct official size.
  166.      * (Catch evil compilers that do struct padding.)
  167.      */
  168.     assert(sizeof(struct bootp) == BP_MINPKTSZ);
  169.  
  170.     if (uname(&my_uname) < 0) {
  171.         fprintf(stderr, "%s: can't get hostname\n", argv[0]);
  172.         exit(1);
  173.     }
  174.     hostname = my_uname.nodename;
  175.  
  176.     sndbuf = malloc(BUFLEN);
  177.     rcvbuf = malloc(BUFLEN);
  178.     if (!sndbuf || !rcvbuf) {
  179.         printf("malloc failed\n");
  180.         exit(1);
  181.     }
  182.  
  183.     /* default magic number */
  184.     bcopy(vm_rfc1048, (char*)&vend_magic, 4);
  185.  
  186.     /* Handle option switches. */
  187.     while (argc > 0) {
  188.         if (argv[0][0] != '-')
  189.             break;
  190.         switch (argv[0][1]) {
  191.  
  192.         case 'f':                /* File name to reqest. */
  193.             if (argc < 2)
  194.                 goto error;
  195.             argc--; argv++;
  196.             bp_file = *argv;
  197.             break;
  198.  
  199.         case 'h':                /* Use hardware address. */
  200.             use_hwa = 1;
  201.             break;
  202.  
  203.         case 'm':                /* Magic number value. */
  204.             if (argc < 2)
  205.                 goto error;
  206.             argc--; argv++;
  207.             vend_magic = inet_addr(*argv);
  208.             break;
  209.  
  210.         error:
  211.         default:
  212.             puts(usage);
  213.             exit(1);
  214.  
  215.         }
  216.         argc--;
  217.         argv++;
  218.     }
  219.  
  220.     /* Get server name (or address) for query. */
  221.     if (argc > 0) {
  222.         servername = *argv;
  223.         argc--;
  224.         argv++;
  225.     }
  226.     /* Get optional vendor-data-template-file. */
  227.     if (argc > 0) {
  228.         vendor_file = *argv;
  229.         argc--;
  230.         argv++;
  231.     }
  232.     if (!servername) {
  233.         printf("missing server name.\n");
  234.         puts(usage);
  235.         exit(1);
  236.     }
  237.     /*
  238.      * Create a socket.
  239.      */
  240.     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  241.         perror("socket");
  242.         exit(1);
  243.     }
  244.     /*
  245.      * Get server's listening port number
  246.      */
  247.     sep = getservbyname("sbootp", "udp");
  248.     if (sep) {
  249.         bootps_port = ntohs((u_short) sep->s_port);
  250.     } else {
  251.         fprintf(stderr, "udp/bootps: unknown service -- using port %d\n",
  252.                 IPPORT_BOOTPS);
  253.         bootps_port = (u_short) IPPORT_BOOTPS;
  254.     }
  255.  
  256.     /*
  257.      * Set up server socket address (for send)
  258.      */
  259.     if (servername) {
  260.         if (isdigit(servername[0]))
  261.             server_addr = inet_addr(servername);
  262.         else {
  263.             hep = gethostbyname(servername);
  264.             if (!hep) {
  265.                 fprintf(stderr, "%s: unknown host\n", servername);
  266.                 exit(1);
  267.             }
  268.             bcopy(hep->h_addr, &server_addr, sizeof(server_addr));
  269.         }
  270.     } else {
  271.         /* Get broadcast address */
  272.         /* XXX - not yet */
  273.         server_addr = INADDR_ANY;
  274.     }
  275.     sin_server.sin_family = AF_INET;
  276.     sin_server.sin_port = htons(bootps_port);
  277.     sin_server.sin_addr.s_addr = server_addr;
  278.  
  279.     /*
  280.      * Get client's listening port number
  281.      */
  282.     sep = getservbyname("cbootp", "udp");
  283.     if (sep) {
  284.         bootpc_port = ntohs(sep->s_port);
  285.     } else {
  286.         fprintf(stderr, "udp/bootpc: unknown service -- using port %d\n",
  287.                 IPPORT_BOOTPC);
  288.         bootpc_port = (u_short) IPPORT_BOOTPC;
  289.     }
  290.  
  291.     /*
  292.      * Set up client socket address (for listen)
  293.      */
  294.     sin_client.sin_family = AF_INET;
  295.     sin_client.sin_port = htons(bootpc_port);
  296.     sin_client.sin_addr.s_addr = INADDR_ANY;
  297.  
  298.     /*
  299.      * Bind client socket to BOOTPC port.
  300.      */
  301.     if (bind(s, (struct sockaddr *) &sin_client, sizeof(sin_client)) < 0) {
  302.         perror("bind BOOTPC port");
  303.         if (errno == EACCES)
  304.             fprintf(stderr, "You need to run this as root\n");
  305.         exit(1);
  306.     }
  307.     /*
  308.      * Build a request.
  309.      */
  310.     bp = (struct bootp *) sndbuf;
  311.     bzero(bp, sizeof(*bp));
  312.     bp->bp_op = BOOTREQUEST;
  313.     xid = (int32) getpid();
  314.     bp->bp_xid = (u_int32) htonl(xid);
  315.     if (bp_file)
  316.         strncpy(bp->bp_file, bp_file, BP_FILE_LEN);
  317.  
  318.     /*
  319.      * Fill in the hardware address (or client IP address)
  320.      */
  321.     if (use_hwa) {
  322.         struct ifreq *ifr;
  323.  
  324.         ifr = getif(s, &sin_server.sin_addr);
  325.         if (!ifr) {
  326.             printf("No interface for %s\n", servername);
  327.             exit(1);
  328.         }
  329.         if (getether(ifr->ifr_name, (char*)eaddr)) {
  330.             printf("Can not get ether addr for %s\n", ifr->ifr_name);
  331.             exit(1);
  332.         }
  333.         /* Copy Ethernet address into request packet. */
  334.         bp->bp_htype = 1;
  335.         bp->bp_hlen = 6;
  336.         bcopy(eaddr, bp->bp_chaddr, bp->bp_hlen);
  337.     } else {
  338.         /* Fill in the client IP address. */
  339.         hep = gethostbyname(hostname);
  340.         if (!hep) {
  341.             printf("Can not get my IP address\n");
  342.             exit(1);
  343.         }
  344.         bcopy(hep->h_addr, &bp->bp_ciaddr, hep->h_length);
  345.     }
  346.  
  347.     /*
  348.      * Copy in the default vendor data.
  349.      */
  350.     bcopy((char*)&vend_magic, bp->bp_vend, 4);
  351.     if (vend_magic)
  352.         bp->bp_vend[4] = TAG_END;
  353.  
  354.     /*
  355.      * Read in the "options" part of the request.
  356.      * This also determines the size of the packet.
  357.      */
  358.     snaplen = sizeof(*bp);
  359.     if (vendor_file) {
  360.         int fd = open(vendor_file, 0);
  361.         if (fd < 0) {
  362.             perror(vendor_file);
  363.             exit(1);
  364.         }
  365.         /* Compute actual space for options. */
  366.         n = BUFLEN - sizeof(*bp) + BP_VEND_LEN;
  367.         n = read(fd, bp->bp_vend, n);
  368.         close(fd);
  369.         if (n < 0) {
  370.             perror(vendor_file);
  371.             exit(1);
  372.         }
  373.         printf("read %d bytes of vendor template\n", n);
  374.         if (n > BP_VEND_LEN) {
  375.             printf("warning: extended options in use (len > %d)\n",
  376.                    BP_VEND_LEN);
  377.             snaplen += (n - BP_VEND_LEN);
  378.         }
  379.     }
  380.     /*
  381.      * Set globals needed by print_bootp
  382.      * (called by send_request)
  383.      */
  384.     packetp = (unsigned char *) eaddr;
  385.     snapend = (unsigned char *) sndbuf + snaplen;
  386.  
  387.     /* Send a request once per second while waiting for replies. */
  388.     recvcnt = 0;
  389.     bp->bp_secs = secs = 0;
  390.     send_request(s);
  391.     while (1) {
  392.         struct timeval tv;
  393.         int readfds;
  394.  
  395.         tv.tv_sec = WAITSECS;
  396.         tv.tv_usec = 0L;
  397.         readfds = (1 << s);
  398.         n = select(s + 1, (fd_set *) & readfds, NULL, NULL, &tv);
  399.         if (n < 0) {
  400.             perror("select");
  401.             break;
  402.         }
  403.         if (n == 0) {
  404.             /*
  405.              * We have not received a response in the last second.
  406.              * If we have ever received any responses, exit now.
  407.              * Otherwise, bump the "wait time" field and re-send.
  408.              */
  409.             if (recvcnt > 0)
  410.                 exit(0);
  411.             secs += WAITSECS;
  412.             if (secs > MAXWAIT)
  413.                 break;
  414.             bp->bp_secs = htons(secs);
  415.             send_request(s);
  416.             continue;
  417.         }
  418.         fromlen = sizeof(sin_from);
  419.         n = recvfrom(s, rcvbuf, BUFLEN, 0,
  420.                      (struct sockaddr *) &sin_from, &fromlen);
  421.         if (n <= 0) {
  422.             continue;
  423.         }
  424.         if (n < sizeof(struct bootp)) {
  425.             printf("received short packet\n");
  426.             continue;
  427.         }
  428.         recvcnt++;
  429.  
  430.         /* Print the received packet. */
  431.         printf("Recvd from %s", inet_ntoa(sin_from.sin_addr));
  432.         /* set globals needed by bootp_print() */
  433.         snaplen = n;
  434.         snapend = (unsigned char *) rcvbuf + snaplen;
  435.         bootp_print(rcvbuf, n, sin_from.sin_port, 0);
  436.         putchar('\n');
  437.         /*
  438.          * This no longer exits immediately after receiving
  439.          * one response because it is useful to know if the
  440.          * client might get multiple responses.  This code
  441.          * will now listen for one second after a response.
  442.          */
  443.     }
  444.     fprintf(stderr, "no response from %s\n", servername);
  445.     exit(1);
  446. }
  447.  
  448. static void
  449. send_request(s)
  450.     int s;
  451. {
  452.     /* Print the request packet. */
  453.     printf("Sending to %s", inet_ntoa(sin_server.sin_addr));
  454.     bootp_print(sndbuf, snaplen, sin_from.sin_port, 0);
  455.     putchar('\n');
  456.  
  457.     /* Send the request packet. */
  458.     if (sendto(s, sndbuf, snaplen, 0,
  459.                (struct sockaddr *) &sin_server,
  460.                sizeof(sin_server)) < 0)
  461.     {
  462.         perror("sendto server");
  463.         exit(1);
  464.     }
  465. }
  466.  
  467. /*
  468.  * Print out a filename (or other ascii string).
  469.  * Return true if truncated.
  470.  */
  471. int
  472. printfn(s, ep)
  473.     register u_char *s, *ep;
  474. {
  475.     register u_char c;
  476.  
  477.     putchar('"');
  478.     while ((c = *s++) != '\0') {
  479.         if (s > ep) {
  480.             putchar('"');
  481.             return (1);
  482.         }
  483.         if (!isascii(c)) {
  484.             c = toascii(c);
  485.             putchar('M');
  486.             putchar('-');
  487.         }
  488.         if (!isprint(c)) {
  489.             c ^= 0x40;            /* DEL to ?, others to alpha */
  490.             putchar('^');
  491.         }
  492.         putchar(c);
  493.     }
  494.     putchar('"');
  495.     return (0);
  496. }
  497.  
  498. /*
  499.  * Convert an IP addr to a string.
  500.  * (like inet_ntoa, but ina is a pointer)
  501.  */
  502. char *
  503. ipaddr_string(ina)
  504.     struct in_addr *ina;
  505. {
  506.     static char b[24];
  507.     u_char *p;
  508.  
  509.     p = (u_char *) ina;
  510.     sprintf(b, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
  511.     return (b);
  512. }
  513.  
  514. /*
  515.  * Local Variables:
  516.  * tab-width: 4
  517.  * c-indent-level: 4
  518.  * c-argdecl-indent: 4
  519.  * c-continued-statement-offset: 4
  520.  * c-continued-brace-offset: -4
  521.  * c-label-offset: -4
  522.  * c-brace-offset: 0
  523.  * End:
  524.  */
  525.