Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/libexec/bootpd/dovend.c
34822 views
1
/*
2
* dovend.c : Inserts all but the first few vendor options.
3
*/
4
5
#include <sys/types.h>
6
7
#include <netinet/in.h>
8
#include <arpa/inet.h> /* inet_ntoa */
9
10
#include <stdlib.h>
11
#include <stdio.h>
12
#include <string.h>
13
#include <errno.h>
14
#include <syslog.h>
15
16
#include "bootp.h"
17
#include "bootpd.h"
18
#include "report.h"
19
#include "dovend.h"
20
21
PRIVATE int insert_generic(struct shared_bindata *, byte **, int *);
22
23
/*
24
* Insert the 2nd part of the options into an option buffer.
25
* Return amount of space used.
26
*
27
* This inserts everything EXCEPT:
28
* magic cookie, subnet mask, gateway, bootsize, extension file
29
* Those are handled separately (in bootpd.c) to allow this function
30
* to be shared between bootpd and bootpef.
31
*
32
* When an "extension file" is in use, the options inserted by
33
* this function go into the exten_file, not the bootp response.
34
*/
35
36
int
37
dovend_rfc1497(struct host *hp, byte *buf, int len)
38
{
39
int bytesleft = len;
40
byte *vp = buf;
41
42
static const char noroom[] = "%s: No room for \"%s\" option";
43
#define NEED(LEN, MSG) do \
44
if (bytesleft < (LEN)) { \
45
report(LOG_NOTICE, noroom, \
46
hp->hostname->string, MSG); \
47
return (vp - buf); \
48
} while (0)
49
50
/*
51
* Note that the following have already been inserted:
52
* magic_cookie, subnet_mask, gateway, bootsize
53
*
54
* The remaining options are inserted in order of importance.
55
* (Of course the importance of each is a matter of opinion.)
56
* The option insertion order should probably be configurable.
57
*
58
* This is the order used in the NetBSD version. Can anyone
59
* explain why the time_offset and swap_server are first?
60
* Also, why is the hostname so far down the list? -gwr
61
*/
62
63
if (hp->flags.time_offset) {
64
NEED(6, "to");
65
*vp++ = TAG_TIME_OFFSET;/* -1 byte */
66
*vp++ = 4; /* -1 byte */
67
insert_u_long(htonl(hp->time_offset), &vp); /* -4 bytes */
68
bytesleft -= 6;
69
}
70
/*
71
* swap server, root path, dump path
72
*/
73
if (hp->flags.swap_server) {
74
NEED(6, "sw");
75
/* There is just one SWAP_SERVER, so it is not an iplist. */
76
*vp++ = TAG_SWAP_SERVER;/* -1 byte */
77
*vp++ = 4; /* -1 byte */
78
insert_u_long(hp->swap_server.s_addr, &vp); /* -4 bytes */
79
bytesleft -= 6; /* Fix real count */
80
}
81
if (hp->flags.root_path) {
82
/*
83
* Check for room for root_path. Add 2 to account for
84
* TAG_ROOT_PATH and length.
85
*/
86
len = strlen(hp->root_path->string);
87
NEED((len + 2), "rp");
88
*vp++ = TAG_ROOT_PATH;
89
*vp++ = (byte) (len & 0xFF);
90
bcopy(hp->root_path->string, vp, len);
91
vp += len;
92
bytesleft -= len + 2;
93
}
94
if (hp->flags.dump_file) {
95
/*
96
* Check for room for dump_file. Add 2 to account for
97
* TAG_DUMP_FILE and length.
98
*/
99
len = strlen(hp->dump_file->string);
100
NEED((len + 2), "df");
101
*vp++ = TAG_DUMP_FILE;
102
*vp++ = (byte) (len & 0xFF);
103
bcopy(hp->dump_file->string, vp, len);
104
vp += len;
105
bytesleft -= len + 2;
106
}
107
/*
108
* DNS server and domain
109
*/
110
if (hp->flags.domain_server) {
111
if (insert_ip(TAG_DOMAIN_SERVER,
112
hp->domain_server,
113
&vp, &bytesleft))
114
NEED(8, "ds");
115
}
116
if (hp->flags.domain_name) {
117
/*
118
* Check for room for domain_name. Add 2 to account for
119
* TAG_DOMAIN_NAME and length.
120
*/
121
len = strlen(hp->domain_name->string);
122
NEED((len + 2), "dn");
123
*vp++ = TAG_DOMAIN_NAME;
124
*vp++ = (byte) (len & 0xFF);
125
bcopy(hp->domain_name->string, vp, len);
126
vp += len;
127
bytesleft -= len + 2;
128
}
129
/*
130
* NIS (YP) server and domain
131
*/
132
if (hp->flags.nis_server) {
133
if (insert_ip(TAG_NIS_SERVER,
134
hp->nis_server,
135
&vp, &bytesleft))
136
NEED(8, "ys");
137
}
138
if (hp->flags.nis_domain) {
139
/*
140
* Check for room for nis_domain. Add 2 to account for
141
* TAG_NIS_DOMAIN and length.
142
*/
143
len = strlen(hp->nis_domain->string);
144
NEED((len + 2), "yn");
145
*vp++ = TAG_NIS_DOMAIN;
146
*vp++ = (byte) (len & 0xFF);
147
bcopy(hp->nis_domain->string, vp, len);
148
vp += len;
149
bytesleft -= len + 2;
150
}
151
/* IEN 116 name server */
152
if (hp->flags.name_server) {
153
if (insert_ip(TAG_NAME_SERVER,
154
hp->name_server,
155
&vp, &bytesleft))
156
NEED(8, "ns");
157
}
158
if (hp->flags.rlp_server) {
159
if (insert_ip(TAG_RLP_SERVER,
160
hp->rlp_server,
161
&vp, &bytesleft))
162
NEED(8, "rl");
163
}
164
/* Time server (RFC 868) */
165
if (hp->flags.time_server) {
166
if (insert_ip(TAG_TIME_SERVER,
167
hp->time_server,
168
&vp, &bytesleft))
169
NEED(8, "ts");
170
}
171
/* NTP (time) Server (RFC 1129) */
172
if (hp->flags.ntp_server) {
173
if (insert_ip(TAG_NTP_SERVER,
174
hp->ntp_server,
175
&vp, &bytesleft))
176
NEED(8, "nt");
177
}
178
/*
179
* I wonder: If the hostname were "promoted" into the BOOTP
180
* response part, might these "extension" files possibly be
181
* shared between several clients?
182
*
183
* Also, why not just use longer BOOTP packets with all the
184
* additional length used as option data. This bootpd version
185
* already supports that feature by replying with the same
186
* packet length as the client request packet. -gwr
187
*/
188
if (hp->flags.name_switch && hp->flags.send_name) {
189
/*
190
* Check for room for hostname. Add 2 to account for
191
* TAG_HOST_NAME and length.
192
*/
193
len = strlen(hp->hostname->string);
194
#if 0
195
/*
196
* XXX - Too much magic. The user can always set the hostname
197
* to the short version in the bootptab file. -gwr
198
*/
199
if ((len + 2) > bytesleft) {
200
/*
201
* Not enough room for full (domain-qualified) hostname, try
202
* stripping it down to just the first field (host).
203
*/
204
char *tmpstr = hp->hostname->string;
205
len = 0;
206
while (*tmpstr && (*tmpstr != '.')) {
207
tmpstr++;
208
len++;
209
}
210
}
211
#endif
212
NEED((len + 2), "hn");
213
*vp++ = TAG_HOST_NAME;
214
*vp++ = (byte) (len & 0xFF);
215
bcopy(hp->hostname->string, vp, len);
216
vp += len;
217
bytesleft -= len + 2;
218
}
219
/*
220
* The rest of these are less important, so they go last.
221
*/
222
if (hp->flags.lpr_server) {
223
if (insert_ip(TAG_LPR_SERVER,
224
hp->lpr_server,
225
&vp, &bytesleft))
226
NEED(8, "lp");
227
}
228
if (hp->flags.cookie_server) {
229
if (insert_ip(TAG_COOKIE_SERVER,
230
hp->cookie_server,
231
&vp, &bytesleft))
232
NEED(8, "cs");
233
}
234
if (hp->flags.log_server) {
235
if (insert_ip(TAG_LOG_SERVER,
236
hp->log_server,
237
&vp, &bytesleft))
238
NEED(8, "lg");
239
}
240
/*
241
* XXX - Add new tags here (to insert options)
242
*/
243
if (hp->flags.generic) {
244
if (insert_generic(hp->generic, &vp, &bytesleft))
245
NEED(64, "(generic)");
246
}
247
/*
248
* The end marker is inserted by the caller.
249
*/
250
return (vp - buf);
251
#undef NEED
252
} /* dovend_rfc1497 */
253
254
255
256
/*
257
* Insert a tag value, a length value, and a list of IP addresses into the
258
* memory buffer indirectly pointed to by "dest". "tag" is the RFC1048 tag
259
* number to use, "iplist" is a pointer to a list of IP addresses
260
* (struct in_addr_list), and "bytesleft" points to an integer which
261
* indicates the size of the "dest" buffer.
262
*
263
* Return zero if everything fits.
264
*
265
* This is used to fill the vendor-specific area of a bootp packet in
266
* conformance to RFC1048.
267
*/
268
269
int
270
insert_ip(byte tag, struct in_addr_list *iplist, byte **dest, int *bytesleft)
271
{
272
struct in_addr *addrptr;
273
unsigned addrcount = 1;
274
byte *d;
275
276
if (iplist == NULL)
277
return (0);
278
279
if (*bytesleft >= 6) {
280
d = *dest; /* Save pointer for later */
281
**dest = tag;
282
(*dest) += 2;
283
(*bytesleft) -= 2; /* Account for tag and length */
284
addrptr = iplist->addr;
285
addrcount = iplist->addrcount;
286
while ((*bytesleft >= 4) && (addrcount > 0)) {
287
insert_u_long(addrptr->s_addr, dest);
288
addrptr++;
289
addrcount--;
290
(*bytesleft) -= 4; /* Four bytes per address */
291
}
292
d[1] = (byte) ((*dest - d - 2) & 0xFF);
293
}
294
return (addrcount);
295
}
296
297
298
299
/*
300
* Insert generic data into a bootp packet. The data is assumed to already
301
* be in RFC1048 format. It is inserted using a first-fit algorithm which
302
* attempts to insert as many tags as possible. Tags and data which are
303
* too large to fit are skipped; any remaining tags are tried until they
304
* have all been exhausted.
305
* Return zero if everything fits.
306
*/
307
308
static int
309
insert_generic(struct shared_bindata *gendata, byte **buff, int *bytesleft)
310
{
311
byte *srcptr;
312
int length, numbytes;
313
int skipped = 0;
314
315
if (gendata == NULL)
316
return (0);
317
318
srcptr = gendata->data;
319
length = gendata->length;
320
while ((length > 0) && (*bytesleft > 0)) {
321
switch (*srcptr) {
322
case TAG_END:
323
length = 0; /* Force an exit on next iteration */
324
break;
325
case TAG_PAD:
326
*(*buff)++ = *srcptr++;
327
(*bytesleft)--;
328
length--;
329
break;
330
default:
331
numbytes = srcptr[1] + 2;
332
if (*bytesleft < numbytes)
333
skipped += numbytes;
334
else {
335
bcopy(srcptr, *buff, numbytes);
336
(*buff) += numbytes;
337
(*bytesleft) -= numbytes;
338
}
339
srcptr += numbytes;
340
length -= numbytes;
341
break;
342
}
343
} /* while */
344
return (skipped);
345
}
346
347
/*
348
* Insert the unsigned long "value" into memory starting at the byte
349
* pointed to by the byte pointer (*dest). (*dest) is updated to
350
* point to the next available byte.
351
*
352
* Since it is desirable to internally store network addresses in network
353
* byte order (in struct in_addr's), this routine expects longs to be
354
* passed in network byte order.
355
*
356
* However, due to the nature of the main algorithm, the long must be in
357
* host byte order, thus necessitating the use of ntohl() first.
358
*/
359
360
void
361
insert_u_long(u_int32 value, byte **dest)
362
{
363
byte *temp;
364
int n;
365
366
value = ntohl(value); /* Must use host byte order here */
367
temp = (*dest += 4);
368
for (n = 4; n > 0; n--) {
369
*--temp = (byte) (value & 0xFF);
370
value >>= 8;
371
}
372
/* Final result is network byte order */
373
}
374
375
/*
376
* Local Variables:
377
* tab-width: 4
378
* c-indent-level: 4
379
* c-argdecl-indent: 4
380
* c-continued-statement-offset: 4
381
* c-continued-brace-offset: -4
382
* c-label-offset: -4
383
* c-brace-offset: 0
384
* End:
385
*/
386
387