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