1 /* $NetBSD: bootptest.c,v 1.17 2008/05/02 19:22:10 xtraeme Exp $ */
4 * bootptest.c - Test out a bootp server.
6 * This simple program was put together from pieces taken from
7 * various places, including the CMU BOOTP client and server.
8 * The packet printing routine is from the Berkeley "tcpdump"
9 * program with some enhancements I added. The print-bootp.c
10 * file was shared with my copy of "tcpdump" and therefore uses
11 * some unusual utility routines that would normally be provided
12 * by various parts of the tcpdump program. Gordon W. Ross
16 * This program includes software developed by the University of
17 * California, Lawrence Berkeley Laboratory and its contributors.
18 * (See the copyright notice in print-bootp.c)
20 * The remainder of this program is public domain. You may do
21 * whatever you like with it except claim that you wrote it.
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 * 12/02/93 Released version 1.4 (with bootp-2.3.2)
30 * 11/05/93 Released version 1.3
31 * 10/14/93 Released version 1.2
32 * 10/11/93 Released version 1.1
33 * 09/28/93 Released version 1.0
34 * 09/93 Original developed by Gordon W. Ross <gwr@mc.com>
37 #include <sys/cdefs.h>
39 __RCSID("$NetBSD: bootptest.c,v 1.17 2008/05/02 19:22:10 xtraeme Exp $");
42 const char *usage
= "usage: %s [-f bootfile] [-h] [-m magic_number] server-name\n"
43 " [vendor-data-template-file]\n";
45 #include <sys/param.h>
46 #include <sys/socket.h>
47 #include <sys/ioctl.h>
54 #include <netinet/in.h>
55 #include <arpa/inet.h> /* inet_ntoa */
69 #include "bootptest.h"
72 #include "patchlevel.h"
83 unsigned char *packetp
;
84 unsigned char *snapend
;
89 * IP port numbers for client and server obtained from /etc/services
92 u_short bootps_port
, bootpc_port
;
96 * Internet socket and interface config structures
99 struct sockaddr_in sin_server
; /* where to send requests */
100 struct sockaddr_in sin_client
; /* for bind and listen */
101 struct sockaddr_in sin_from
; /* Packet source */
102 u_char eaddr
[16]; /* Ethernet address */
108 int debug
= 1; /* Debugging flag (level) */
109 char hostname
[MAXHOSTNAMELEN
+ 1];
110 char *sndbuf
; /* Send packet buffer */
111 char *rcvbuf
; /* Receive packet buffer */
114 * Vendor magic cookies for CMU and RFC1048
117 unsigned char vm_cmu
[4] = VM_CMU
;
118 unsigned char vm_rfc1048
[4] = VM_RFC1048
;
119 short secs
; /* How long client has waited */
122 extern int getether(char *, char *);
123 int main(int, char **);
124 void send_request(int);
127 * Initialization such as command-line processing is done, then
128 * the receiver loop is started. Die when interrupted.
132 main(int argc
, char **argv
)
138 char *servername
= NULL
;
139 char *vendor_file
= NULL
;
140 char *bp_file
= NULL
;
142 int s
; /* Socket file descriptor */
147 struct pollfd set
[1];
149 progname
= strrchr(argv
[0], '/');
158 printf("%s: version %s.%d\n", progname
, VERSION
, PATCHLEVEL
);
161 * Verify that "struct bootp" has the correct official size.
162 * (Catch evil compilers that do struct padding.)
164 assert(sizeof(struct bootp
) == BP_MINPKTSZ
);
166 sndbuf
= malloc(BUFLEN
);
167 rcvbuf
= malloc(BUFLEN
);
168 if (!sndbuf
|| !rcvbuf
) {
169 printf("malloc failed\n");
173 /* default magic number */
174 bcopy(vm_rfc1048
, (char*)&vend_magic
, 4);
176 /* Handle option switches. */
178 if (argv
[0][0] != '-')
180 switch (argv
[0][1]) {
182 case 'f': /* File name to reqest. */
189 case 'h': /* Use hardware address. */
193 case 'm': /* Magic number value. */
197 vend_magic
= inet_addr(*argv
);
202 (void)fprintf(stderr
, usage
, getprogname());
210 /* Get server name (or address) for query. */
216 /* Get optional vendor-data-template-file. */
223 printf("missing server name.\n");
224 (void)fprintf(stderr
, usage
, getprogname());
230 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
235 * Get server's listening port number
237 sep
= getservbyname("bootps", "udp");
239 bootps_port
= ntohs((u_short
) sep
->s_port
);
241 fprintf(stderr
, "udp/bootps: unknown service -- using port %d\n",
243 bootps_port
= (u_short
) IPPORT_BOOTPS
;
247 * Set up server socket address (for send)
250 if (inet_aton(servername
, &sin_server
.sin_addr
) == 0) {
251 hep
= gethostbyname(servername
);
253 fprintf(stderr
, "%s: unknown host\n", servername
);
256 memcpy(&sin_server
.sin_addr
, hep
->h_addr
,
257 sizeof(sin_server
.sin_addr
));
260 /* Get broadcast address */
262 sin_server
.sin_addr
.s_addr
= INADDR_ANY
;
264 sin_server
.sin_family
= AF_INET
;
265 sin_server
.sin_port
= htons(bootps_port
);
268 * Get client's listening port number
270 sep
= getservbyname("bootpc", "udp");
272 bootpc_port
= ntohs(sep
->s_port
);
274 fprintf(stderr
, "udp/bootpc: unknown service -- using port %d\n",
276 bootpc_port
= (u_short
) IPPORT_BOOTPC
;
280 * Set up client socket address (for listen)
282 sin_client
.sin_family
= AF_INET
;
283 sin_client
.sin_port
= htons(bootpc_port
);
284 sin_client
.sin_addr
.s_addr
= INADDR_ANY
;
287 * Bind client socket to BOOTPC port.
289 if (bind(s
, (struct sockaddr
*) &sin_client
, sizeof(sin_client
)) < 0) {
290 perror("bind BOOTPC port");
292 fprintf(stderr
, "You need to run this as root\n");
298 bp
= (struct bootp
*) sndbuf
;
299 bzero(bp
, sizeof(*bp
));
300 bp
->bp_op
= BOOTREQUEST
;
301 xid
= (int32
) getpid();
302 bp
->bp_xid
= (u_int32
) htonl(xid
);
304 strlcpy(bp
->bp_file
, bp_file
, sizeof(bp
->bp_file
));
307 * Fill in the hardware address (or client IP address)
312 ifr
= getif(s
, &sin_server
.sin_addr
);
314 printf("No interface for %s\n", servername
);
317 if (getether(ifr
->ifr_name
, (char *)eaddr
)) {
318 printf("Can not get ether addr for %s\n", ifr
->ifr_name
);
321 /* Copy Ethernet address into request packet. */
324 bcopy(eaddr
, bp
->bp_chaddr
, bp
->bp_hlen
);
326 /* Fill in the client IP address. */
327 gethostname(hostname
, sizeof(hostname
));
328 hostname
[sizeof(hostname
) - 1] = '\0';
329 hep
= gethostbyname(hostname
);
331 printf("Can not get my IP address\n");
334 bcopy(hep
->h_addr
, &bp
->bp_ciaddr
, hep
->h_length
);
338 * Copy in the default vendor data.
340 bcopy((char*)&vend_magic
, bp
->bp_vend
, 4);
342 bp
->bp_vend
[4] = TAG_END
;
345 * Read in the "options" part of the request.
346 * This also determines the size of the packet.
348 snaplen
= sizeof(*bp
);
350 int fd
= open(vendor_file
, 0);
355 /* Compute actual space for options. */
356 n
= BUFLEN
- sizeof(*bp
) + BP_VEND_LEN
;
357 n
= read(fd
, bp
->bp_vend
, n
);
363 printf("read %d bytes of vendor template\n", n
);
364 if (n
> BP_VEND_LEN
) {
365 printf("warning: extended options in use (len > %d)\n",
367 snaplen
+= (n
- BP_VEND_LEN
);
371 * Set globals needed by print_bootp
372 * (called by send_request)
374 packetp
= (unsigned char *) eaddr
;
375 snapend
= (unsigned char *) sndbuf
+ snaplen
;
377 /* Send a request once per second while waiting for replies. */
379 bp
->bp_secs
= secs
= 0;
382 set
[0].events
= POLLIN
;
384 n
= poll(set
, 1, WAITSECS
* 1000);
391 * We have not received a response in the last second.
392 * If we have ever received any responses, exit now.
393 * Otherwise, bump the "wait time" field and re-send.
400 bp
->bp_secs
= htons(secs
);
404 fromlen
= sizeof(sin_from
);
405 n
= recvfrom(s
, rcvbuf
, BUFLEN
, 0,
406 (struct sockaddr
*) &sin_from
, &fromlen
);
410 if (n
< (int)sizeof(struct bootp
)) {
411 printf("received short packet\n");
416 /* Print the received packet. */
417 printf("Recvd from %s", inet_ntoa(sin_from
.sin_addr
));
418 /* set globals needed by bootp_print() */
420 snapend
= (unsigned char *) rcvbuf
+ snaplen
;
421 bootp_print((struct bootp
*)rcvbuf
, n
, sin_from
.sin_port
, 0);
424 * This no longer exits immediately after receiving
425 * one response because it is useful to know if the
426 * client might get multiple responses. This code
427 * will now listen for one second after a response.
430 fprintf(stderr
, "no response from %s\n", servername
);
437 /* Print the request packet. */
438 printf("Sending to %s", inet_ntoa(sin_server
.sin_addr
));
439 bootp_print((struct bootp
*)sndbuf
, snaplen
, sin_from
.sin_port
, 0);
442 /* Send the request packet. */
443 if (sendto(s
, sndbuf
, snaplen
, 0,
444 (struct sockaddr
*) &sin_server
,
445 sizeof(sin_server
)) < 0)
447 perror("sendto server");
453 * Print out a filename (or other ascii string).
454 * Return true if truncated.
457 printfn(u_char
*s
, u_char
*ep
)
462 while ((c
= *s
++) != 0) {
473 c
^= 0x40; /* DEL to ?, others to alpha */
483 * Convert an IP addr to a string.
484 * (like inet_ntoa, but ina is a pointer)
487 ipaddr_string(struct in_addr
*ina
)
493 snprintf(b
, sizeof(b
), "%d.%d.%d.%d", p
[0], p
[1], p
[2], p
[3]);
501 * c-argdecl-indent: 4
502 * c-continued-statement-offset: 4
503 * c-continued-brace-offset: -4