home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume27 / bootptest-1.1 / part01 / bootptest.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-11  |  8.0 KB  |  348 lines

  1. /*
  2.  * bootptest.c - Test out a bootp server.
  3.  *
  4.  *
  5.  */
  6. char *usage = "bootptest server-name [vendor-data-template-file]";
  7.  
  8. #include <sys/types.h>
  9. #include <sys/socket.h>
  10. #include <sys/ioctl.h>
  11. #include <sys/file.h>
  12. #include <sys/time.h>
  13. #include <sys/stat.h>
  14. #include <net/if.h>
  15. #ifdef sun
  16. #include <sys/sockio.h>
  17. #include <net/if_arp.h>
  18. #endif
  19. #include <netinet/in.h>
  20. #include <netinet/if_ether.h>
  21. #include <signal.h>
  22. #include <stdio.h>
  23. #include <strings.h>
  24. #include <errno.h>
  25. #include <ctype.h>
  26. #include <netdb.h>
  27.  
  28. extern int sys_nerr;
  29. extern char *sys_errlist[];
  30.  
  31. #include "bootp.h"
  32. #include "interface.h"
  33.  
  34. #define get_network_errmsg get_errmsg
  35. #define LOG_ERR 1
  36. #define BUFLEN 1024
  37.  
  38. int vflag = 1;
  39. int tflag = 0;
  40. int thiszone;
  41. char *program_name;
  42. unsigned char *packetp;
  43. unsigned char *snapend;
  44. int snaplen;
  45.  
  46.  
  47. /*
  48.  * IP port numbers for client and server obtained from /etc/services
  49.  */
  50.  
  51. u_short bootps_port, bootpc_port;
  52.  
  53.  
  54. /*
  55.  * Internet socket and interface config structures
  56.  */
  57.  
  58. struct sockaddr_in sin_server;
  59. struct sockaddr_in sin_client;
  60. struct sockaddr_in sin_from;    /* Packet source */
  61. struct ifreq ifreq[10];        /* Holds interface configuration */
  62. struct ifconf ifconf;        /* Int. config ioctl block (pnts to ifreq) */
  63. struct arpreq arpreq;        /* Arp request ioctl block */
  64. struct ether_addr eaddr;
  65.  
  66. /*
  67.  * General
  68.  */
  69.  
  70. int debug = 0;                /* Debugging flag (level) */
  71. int s;                    /* Socket file descriptor */
  72. char hostname[64];
  73. unsigned char buf[BUFLEN];        /* Receive packet buffer */
  74. struct timezone tzp;            /* Time zone offset for clients */
  75. struct timeval tp;            /* Time (extra baggage) */
  76. long secondswest;            /* Time zone offset in seconds */
  77.  
  78. /*
  79.  * Vendor magic cookies for CMU and RFC1048
  80.  */
  81.  
  82. unsigned char vm_cmu[4]        = VM_CMU;
  83. unsigned char vm_rfc1048[4] = VM_RFC1048;
  84.  
  85. void report();
  86. char * get_errmsg();
  87. extern void bootp_print();
  88. extern struct ether_addr *ether_hostton();
  89.  
  90. /*
  91.  * Initialization such as command-line processing is done, then
  92.  * the receiver loop is started.  Die when interrupted.
  93.  */
  94.  
  95. main(argc, argv)
  96.     int argc;
  97.     char **argv;
  98. {
  99.     struct timeval timenow;
  100.     struct bootp *bp = (struct bootp *) buf;
  101.     struct servent *sep;
  102.     struct hostent *hep;
  103.     
  104.     int n, tolen, fromlen;
  105.     int nfound, readfds;
  106.     char *servername = NULL;
  107.     char *vendor_file = NULL;
  108.     long server_addr = INADDR_ANY;
  109.     
  110.     program_name = argv[0];
  111.     
  112.     /* Get my Ethernet address for the query. */
  113.     gethostname(hostname, sizeof(hostname));
  114.     if (ether_hostton(hostname, &eaddr)) {
  115.     printf("Can not get my ethernet address\n");
  116.     exit(1);
  117.     }
  118.     
  119.     /* If server name given, query there, otherwise use broadcast. */
  120.     if (argc <= 1) {
  121.     printf("missing server name.\n");
  122.     puts(usage);
  123.     exit(1);
  124.     }
  125.     servername = argv[1];
  126.     
  127.     /* vendor-data-template-file */
  128.     if (argc > 2) vendor_file = argv[2];
  129.     
  130.     /*
  131.      * Create a socket.
  132.      */
  133.     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  134.     report(LOG_ERR, "socket: %s\n", get_network_errmsg());
  135.     exit(1);
  136.     }
  137.     
  138.     /*
  139.      * Determine network configuration.
  140.      */
  141.     ifconf.ifc_len = sizeof(ifreq);
  142.     ifconf.ifc_req = ifreq;
  143.     if ((ioctl(s, SIOCGIFCONF, (caddr_t) &ifconf) < 0) ||
  144.     (ifconf.ifc_len <= 0)) {
  145.     report(LOG_ERR, "ioctl: %s\n", get_network_errmsg());
  146.     exit(1);
  147.     }
  148.     /* Find the appropriate interface to use? */
  149.     
  150.     /*
  151.      * Get server's listening port number
  152.      */
  153.     sep = getservbyname("bootps", "udp");
  154.     if (sep) {
  155.     bootps_port = ntohs((u_short) sep->s_port);
  156.     } else {
  157.     report(LOG_ERR,
  158.            "udp/bootps: unknown service -- assuming port %d\n",
  159.            IPPORT_BOOTPS);
  160.     bootps_port = (u_short) IPPORT_BOOTPS;
  161.     }
  162.     
  163.     /*
  164.      * Set up server socket address.
  165.      */
  166.     if (servername) {
  167.     hep = gethostbyname(servername);
  168.     if (!hep) {
  169.         report(LOG_ERR, "gethostbyname(%s)", servername);
  170.         exit(1);
  171.     }
  172.     bcopy(hep->h_addr, &sin_server.sin_addr, sizeof(struct in_addr));
  173.     } else {
  174.     /* Get broadcast address */
  175.     /* XXX - not yet */
  176.     sin_server.sin_addr.s_addr = INADDR_ANY;
  177.     }
  178.     sin_server.sin_family = AF_INET;
  179.     sin_server.sin_port = htons(bootps_port);
  180.     
  181.     /*
  182.      * Get client's listening port number
  183.      */
  184.     sep = getservbyname("bootpc", "udp");
  185.     if (sep) {
  186.     bootpc_port = ntohs(sep->s_port);
  187.     } else {
  188.     report(LOG_ERR,
  189.            "udp/bootpc: unknown service -- assuming port %d\n",
  190.            IPPORT_BOOTPC);
  191.     bootpc_port = (u_short) IPPORT_BOOTPC;
  192.     }
  193.     
  194.     /*
  195.      * Set up client socket address.
  196.      */
  197.     sin_client.sin_family = AF_INET;
  198.     sin_client.sin_addr.s_addr = INADDR_ANY;
  199.     sin_client.sin_port = htons(bootpc_port);
  200.     
  201.     /*
  202.      * Bind client socket to BOOTPC port.
  203.      */
  204.     if (bind(s, &sin_client, sizeof(sin_client)) < 0) {
  205.     perror("bind BOOTPC port");
  206.     fprintf(stderr, "You need to run this as root\n");
  207.     exit(1);
  208.     }
  209.     
  210.     /*
  211.      * Build a request.
  212.      */
  213.     bzero(bp, sizeof(*bp));
  214.     bp->bp_op = BOOTREQUEST;
  215.     bp->bp_htype = 1;
  216.     bp->bp_hlen = 6;
  217.     bp->bp_xid = 2;     /* arbitrary */
  218.     bp->bp_secs = 4;
  219.     
  220.     /*
  221.      * Make the request look like a broadcast type.
  222.      * (supply the hardware address, not the client IP address.)
  223.      */
  224.     bcopy(&eaddr, bp->bp_chaddr, sizeof(eaddr));
  225.     bp->bp_siaddr.s_addr = -1;    /* broadcast address */
  226.  
  227.     /*
  228.      * Read in the "options" part of the request.
  229.      * This also determines the size of the packet.
  230.      */
  231.     snaplen = sizeof(*bp);
  232.     if (vendor_file) {
  233.     int fd = open(vendor_file, 0);
  234.     if (fd < 0) {
  235.         perror(vendor_file);
  236.         exit(1);
  237.     }
  238.     /* Compute actual space for options. */
  239.     n = BUFLEN - sizeof(*bp) + BP_VEND_LEN;
  240.     n = read(fd, bp->bp_vend, n);
  241.     close(fd);
  242.     if (n < 0) {
  243.         perror(vendor_file);
  244.         exit(1);
  245.     }
  246.     printf("read %d bytes of vendor template\n", n);
  247.     if (n > BP_VEND_LEN) {
  248.         printf("warning: extended options in use (len > %d)\n",    
  249.            BP_VEND_LEN);
  250.         snaplen += (n - BP_VEND_LEN);
  251.     }
  252.     }
  253.     /* Set the end pointer for bootp_print() */
  254.     snapend = buf + snaplen;
  255.     
  256.     /* This is used by bootp_print() */
  257.     packetp = (unsigned char*) &eaddr;
  258.     
  259.     /* Print the request packet. */
  260.     printf("Request to %s", inet_ntoa(sin_server.sin_addr));
  261.     printf(" (port:%d)", bootps_port);
  262.     bootp_print(bp, snaplen, sin_from.sin_port, 0);
  263.     putchar('\n');
  264.     
  265.     if (sendto(s, buf, snaplen, 0,
  266.            &sin_server, sizeof(sin_server)) < 0)
  267.     {
  268.     perror("sendto server");
  269.     exit(1);
  270.     }
  271.     
  272.     printf("Receiving...\n");
  273.     alarm(5);    /* XXX - OK? */
  274.     
  275.     while (1) {
  276.     
  277.     fromlen = sizeof(sin_from);
  278.     n = recvfrom(s, buf, sizeof(buf), 0, &sin_from, &fromlen);
  279.     if (n <= 0) {
  280.         continue;
  281.     }
  282.     
  283.     if (n < sizeof(struct bootp)) {
  284.         report(LOG_ERR, "received short packet\n");
  285.         continue;
  286.     }
  287.     
  288.     /* Print the received packet. */
  289.     printf("Packet from %s", inet_ntoa(sin_from.sin_addr));
  290.     printf(" (port:%d)", ntohs(sin_from.sin_port));
  291.     snaplen = n;
  292.     snapend = buf + snaplen;
  293.     bootp_print(bp, n, sin_from.sin_port, 0);
  294.     putchar('\n');
  295.     }
  296. }
  297.  
  298.  
  299.  
  300. /*
  301.  * This routine reports errors and such via stderr and syslog() if
  302.  * appopriate.  It just helps avoid a lot of "#ifdef SYSLOG" constructs
  303.  * from being scattered throughout the code.
  304.  *
  305.  * The syntax is identical to syslog(3), but %m is not considered special
  306.  * for output to stderr (i.e. you'll see "%m" in the output. . .).  Also,
  307.  * control strings should normally end with \n since newlines aren't
  308.  * automatically generated for stderr output (whereas syslog strips out all
  309.  * newlines and adds its own at the end).
  310.  */
  311.  
  312. /*VARARGS2*/
  313. void report(priority, fmt, p0, p1, p2, p3, p4)
  314.     int priority;
  315.     char *fmt;
  316. {
  317.     fprintf(stderr, "bootpd(pri=%d): ", priority);
  318.     fprintf(stderr, fmt, p0, p1, p2, p3, p4);
  319. }
  320.  
  321.  
  322. /*
  323.  * Return pointer to static string which gives full filesystem error message.
  324.  */
  325.  
  326. char *get_errmsg()
  327. {
  328.     static char errmsg[80];
  329.     
  330.     if (errno < sys_nerr) {
  331.     return sys_errlist[errno];
  332.     } else {
  333.     sprintf(errmsg, "Error %d", errno);
  334.     return errmsg;
  335.     }
  336. }
  337.  
  338. #ifndef etheraddr_string
  339. char *etheraddr_string(p)
  340.     char *p;
  341. {
  342.     static char buf[32];
  343.     sprintf(buf, "%x:%x:%x:%x:%x:%x",
  344.         p[0],p[1],p[2],p[3],p[4],p[5]);
  345.     return(buf);
  346. }
  347. #endif
  348.