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