~ubuntu-branches/ubuntu/gutsy/dhcp/gutsy

« back to all changes in this revision

Viewing changes to server/bootp.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Schulze
  • Date: 2004-10-30 21:07:22 UTC
  • Revision ID: james.westby@ubuntu.com-20041030210722-p0u4682vtncfxnnn
Tags: upstream-2.0pl5
ImportĀ upstreamĀ versionĀ 2.0pl5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* bootp.c
 
2
 
 
3
   BOOTP Protocol support. */
 
4
 
 
5
/*
 
6
 * Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium.
 
7
 * All rights reserved.
 
8
 *
 
9
 * Redistribution and use in source and binary forms, with or without
 
10
 * modification, are permitted provided that the following conditions
 
11
 * are met:
 
12
 *
 
13
 * 1. Redistributions of source code must retain the above copyright
 
14
 *    notice, this list of conditions and the following disclaimer.
 
15
 * 2. Redistributions in binary form must reproduce the above copyright
 
16
 *    notice, this list of conditions and the following disclaimer in the
 
17
 *    documentation and/or other materials provided with the distribution.
 
18
 * 3. Neither the name of The Internet Software Consortium nor the names
 
19
 *    of its contributors may be used to endorse or promote products derived
 
20
 *    from this software without specific prior written permission.
 
21
 *
 
22
 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
 
23
 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 
24
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 
25
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
26
 * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
 
27
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
28
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
29
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 
30
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
31
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 
32
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 
33
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
34
 * SUCH DAMAGE.
 
35
 *
 
36
 * This software has been written for the Internet Software Consortium
 
37
 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
 
38
 * Enterprises.  To learn more about the Internet Software Consortium,
 
39
 * see ``http://www.vix.com/isc''.  To learn more about Vixie
 
40
 * Enterprises, see ``http://www.vix.com''.
 
41
 */
 
42
 
 
43
#ifndef lint
 
44
static char copyright[] =
 
45
"$Id: bootp.c,v 1.28.2.9 1999/10/19 17:32:49 mellon Exp $ Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
 
46
#endif /* not lint */
 
47
 
 
48
#include "dhcpd.h"
 
49
 
 
50
void bootp (packet)
 
51
        struct packet *packet;
 
52
{
 
53
        int result;
 
54
        struct host_decl *hp;
 
55
        struct host_decl *host = (struct host_decl *)0;
 
56
        struct packet outgoing;
 
57
        struct dhcp_packet raw;
 
58
        struct sockaddr_in to;
 
59
        struct in_addr from;
 
60
        struct hardware hto;
 
61
        struct tree_cache *options [256];
 
62
        struct subnet *subnet;
 
63
        struct lease *lease;
 
64
        struct iaddr ip_address;
 
65
        int i;
 
66
 
 
67
        if (packet -> raw -> op != BOOTREQUEST)
 
68
                return;
 
69
 
 
70
        note ("BOOTREQUEST from %s via %s%s",
 
71
              print_hw_addr (packet -> raw -> htype,
 
72
                             packet -> raw -> hlen,
 
73
                             packet -> raw -> chaddr),
 
74
              packet -> raw -> giaddr.s_addr
 
75
              ? inet_ntoa (packet -> raw -> giaddr)
 
76
              : packet -> interface -> name,
 
77
              packet -> options_valid ? "" : " (non-rfc1048)");
 
78
 
 
79
 
 
80
 
 
81
        if (!locate_network (packet))
 
82
                return;
 
83
 
 
84
        hp = find_hosts_by_haddr (packet -> raw -> htype,
 
85
                                  packet -> raw -> chaddr,
 
86
                                  packet -> raw -> hlen);
 
87
 
 
88
        lease = find_lease (packet, packet -> shared_network, 0);
 
89
 
 
90
        /* Find an IP address in the host_decl that matches the
 
91
           specified network. */
 
92
        if (hp)
 
93
                subnet = find_host_for_network (&hp, &ip_address,
 
94
                                                packet -> shared_network);
 
95
        else
 
96
                subnet = (struct subnet *)0;
 
97
 
 
98
        if (!subnet) {
 
99
                /* We didn't find an applicable host declaration.
 
100
                   Just in case we may be able to dynamically assign
 
101
                   an address, see if there's a host declaration
 
102
                   that doesn't have an ip address associated with it. */
 
103
                if (hp) {
 
104
                        for (; hp; hp = hp -> n_ipaddr) {
 
105
                                if (!hp -> fixed_addr) {
 
106
                                        host = hp;
 
107
                                        break;
 
108
                                }
 
109
                        }
 
110
                }
 
111
 
 
112
                if (host && (!host -> group -> allow_booting)) {
 
113
                        note ("Ignoring excluded BOOTP client %s",
 
114
                              host -> name
 
115
                              ? host -> name
 
116
                              : print_hw_addr (packet -> raw -> htype,
 
117
                                               packet -> raw -> hlen,
 
118
                                               packet -> raw -> chaddr));
 
119
                        return;
 
120
                }
 
121
                        
 
122
                if (host && (!host -> group -> allow_bootp)) {
 
123
                        note ("Ignoring BOOTP request from client %s",
 
124
                              host -> name
 
125
                              ? host -> name
 
126
                              : print_hw_addr (packet -> raw -> htype,
 
127
                                               packet -> raw -> hlen,
 
128
                                               packet -> raw -> chaddr));
 
129
                        return;
 
130
                }
 
131
                        
 
132
                /* If we've been told not to boot unknown clients,
 
133
                   and we didn't find any host record for this client,
 
134
                   ignore it. */
 
135
                if (!host && !(packet -> shared_network ->
 
136
                               group -> boot_unknown_clients)) {
 
137
                        note ("Ignoring unknown BOOTP client %s via %s",
 
138
                              print_hw_addr (packet -> raw -> htype,
 
139
                                             packet -> raw -> hlen,
 
140
                                             packet -> raw -> chaddr),
 
141
                              packet -> raw -> giaddr.s_addr
 
142
                              ? inet_ntoa (packet -> raw -> giaddr)
 
143
                              : packet -> interface -> name);
 
144
                        return;
 
145
                }
 
146
 
 
147
                /* If we've been told not to boot with bootp on this
 
148
                   network, ignore it. */
 
149
                if (!host &&
 
150
                    !(packet -> shared_network -> group -> allow_bootp)) {
 
151
                        note ("Ignoring BOOTP request from client %s via %s",
 
152
                              print_hw_addr (packet -> raw -> htype,
 
153
                                             packet -> raw -> hlen,
 
154
                                             packet -> raw -> chaddr),
 
155
                              packet -> raw -> giaddr.s_addr
 
156
                              ? inet_ntoa (packet -> raw -> giaddr)
 
157
                              : packet -> interface -> name);
 
158
                        return;
 
159
                }
 
160
 
 
161
                /* If the packet is from a host we don't know and there
 
162
                   are no dynamic bootp addresses on the network it came
 
163
                   in on, drop it on the floor. */
 
164
                if (!(packet -> shared_network -> group -> dynamic_bootp)) {
 
165
                      lose:
 
166
                        note ("No applicable record for BOOTP host %s via %s",
 
167
                              print_hw_addr (packet -> raw -> htype,
 
168
                                             packet -> raw -> hlen,
 
169
                                             packet -> raw -> chaddr),
 
170
                              packet -> raw -> giaddr.s_addr
 
171
                              ? inet_ntoa (packet -> raw -> giaddr)
 
172
                              : packet -> interface -> name);
 
173
                        return;
 
174
                }
 
175
 
 
176
                /* If a lease has already been assigned to this client
 
177
                   and it's still okay to use dynamic bootp on
 
178
                   that lease, reassign it. */
 
179
                if (lease) {
 
180
                        /* If this lease can be used for dynamic bootp,
 
181
                           do so. */
 
182
                        if ((lease -> flags & DYNAMIC_BOOTP_OK)) {
 
183
 
 
184
                                /* If it's not a DYNAMIC_BOOTP lease,
 
185
                                   release it before reassigning it
 
186
                                   so that we don't get a lease
 
187
                                   conflict. */
 
188
                                if (!(lease -> flags & BOOTP_LEASE))
 
189
                                        release_lease (lease);
 
190
 
 
191
                                lease -> host = host;
 
192
                                ack_lease (packet, lease, 0, 0);
 
193
                                return;
 
194
                        }
 
195
 
 
196
                         /* If dynamic BOOTP is no longer allowed for
 
197
                           this lease, set it free. */
 
198
                        release_lease (lease);
 
199
                }
 
200
 
 
201
                /* If there are dynamic bootp addresses that might be
 
202
                   available, try to snag one. */
 
203
                for (lease = packet -> shared_network -> last_lease;
 
204
                     lease && lease -> ends <= cur_time;
 
205
                     lease = lease -> prev) {
 
206
                        if ((lease -> flags & DYNAMIC_BOOTP_OK)) {
 
207
                                lease -> host = host;
 
208
                                ack_lease (packet, lease, 0, 0);
 
209
                                return;
 
210
                        }
 
211
                }
 
212
                goto lose;
 
213
        }
 
214
 
 
215
        /* Make sure we're allowed to boot this client. */
 
216
        if (hp && (!hp -> group -> allow_booting)) {
 
217
                note ("Ignoring excluded BOOTP client %s",
 
218
                      hp -> name);
 
219
                return;
 
220
        }
 
221
                        
 
222
        /* Make sure we're allowed to boot this client with bootp. */
 
223
        if (hp && (!hp -> group -> allow_bootp)) {
 
224
                note ("Ignoring BOOTP request from client %s",
 
225
                      hp -> name);
 
226
                return;
 
227
        }
 
228
                        
 
229
        /* Set up the outgoing packet... */
 
230
        memset (&outgoing, 0, sizeof outgoing);
 
231
        memset (&raw, 0, sizeof raw);
 
232
        outgoing.raw = &raw;
 
233
 
 
234
        /* If we didn't get a known vendor magic number on the way in,
 
235
           just copy the input options to the output. */
 
236
        if (!packet -> options_valid &&
 
237
            !subnet -> group -> always_reply_rfc1048 &&
 
238
            (!hp || !hp -> group -> always_reply_rfc1048)) {
 
239
                memcpy (outgoing.raw -> options,
 
240
                        packet -> raw -> options, DHCP_OPTION_LEN);
 
241
                outgoing.packet_length = BOOTP_MIN_LEN;
 
242
        } else {
 
243
                struct tree_cache netmask_tree;   /*  -- RBF */
 
244
 
 
245
                /* Come up with a list of options that we want to send
 
246
                   to this client.  Start with the per-subnet options,
 
247
                   and then override those with client-specific
 
248
                   options. */
 
249
 
 
250
                memcpy (options, subnet -> group -> options, sizeof options);
 
251
 
 
252
                for (i = 0; i < 256; i++) {
 
253
                        if (hp -> group -> options [i])
 
254
                                options [i] = hp -> group -> options [i];
 
255
                }
 
256
 
 
257
                /* Use the subnet mask from the subnet declaration if no other
 
258
                   mask has been provided. */
 
259
                if (!options [DHO_SUBNET_MASK]) {
 
260
                        options [DHO_SUBNET_MASK] = &netmask_tree;
 
261
                        netmask_tree.flags = TC_TEMPORARY;
 
262
                        netmask_tree.value = lease -> subnet -> netmask.iabuf;
 
263
                        netmask_tree.len = lease -> subnet -> netmask.len;
 
264
                        netmask_tree.buf_size = lease -> subnet -> netmask.len;
 
265
                        netmask_tree.timeout = 0xFFFFFFFF;
 
266
                        netmask_tree.tree = (struct tree *)0;
 
267
                }
 
268
 
 
269
                /* Pack the options into the buffer.  Unlike DHCP, we
 
270
                   can't pack options into the filename and server
 
271
                   name buffers. */
 
272
 
 
273
                outgoing.packet_length =
 
274
                        cons_options (packet, outgoing.raw,
 
275
                                      0, options, 0, 0, 1, (u_int8_t *)0, 0);
 
276
                if (outgoing.packet_length < BOOTP_MIN_LEN)
 
277
                        outgoing.packet_length = BOOTP_MIN_LEN;
 
278
        }
 
279
 
 
280
        /* Take the fields that we care about... */
 
281
        raw.op = BOOTREPLY;
 
282
        raw.htype = packet -> raw -> htype;
 
283
        raw.hlen = packet -> raw -> hlen;
 
284
        memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
 
285
        raw.hops = packet -> raw -> hops;
 
286
        raw.xid = packet -> raw -> xid;
 
287
        raw.secs = packet -> raw -> secs;
 
288
        raw.flags = packet -> raw -> flags;
 
289
        raw.ciaddr = packet -> raw -> ciaddr;
 
290
        memcpy (&raw.yiaddr, ip_address.iabuf, sizeof raw.yiaddr);
 
291
 
 
292
        /* Figure out the address of the next server. */
 
293
        if (hp  && hp -> group -> next_server.len)
 
294
                memcpy (&raw.siaddr, hp -> group -> next_server.iabuf, 4);
 
295
        else if (subnet -> group -> next_server.len)
 
296
                memcpy (&raw.siaddr, subnet -> group -> next_server.iabuf, 4);
 
297
        else if (subnet -> interface_address.len)
 
298
                memcpy (&raw.siaddr, subnet -> interface_address.iabuf, 4);
 
299
        else
 
300
                raw.siaddr = packet -> interface -> primary_address;
 
301
 
 
302
        raw.giaddr = packet -> raw -> giaddr;
 
303
        if (hp -> group -> server_name)
 
304
                strncpy (raw.sname, hp -> group -> server_name,
 
305
                         (sizeof raw.sname));
 
306
        else if (subnet -> group -> server_name)
 
307
                strncpy (raw.sname, subnet -> group -> server_name,
 
308
                         (sizeof raw.sname));
 
309
 
 
310
        if (hp -> group -> filename)
 
311
                strncpy (raw.file, hp -> group -> filename,
 
312
                         (sizeof raw.file));
 
313
        else if (subnet -> group -> filename)
 
314
                strncpy (raw.file, subnet -> group -> filename,
 
315
                         (sizeof raw.file));
 
316
        else
 
317
                memcpy (raw.file, packet -> raw -> file, sizeof raw.file);
 
318
 
 
319
        /* Set up the hardware destination address... */
 
320
        hto.htype = packet -> raw -> htype;
 
321
        hto.hlen = packet -> raw -> hlen;
 
322
        memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
 
323
 
 
324
        from = packet -> interface -> primary_address;
 
325
 
 
326
        /* Report what we're doing... */
 
327
        note ("BOOTREPLY for %s to %s (%s) via %s",
 
328
              piaddr (ip_address), hp -> name,
 
329
              print_hw_addr (packet -> raw -> htype,
 
330
                             packet -> raw -> hlen,
 
331
                             packet -> raw -> chaddr),
 
332
              packet -> raw -> giaddr.s_addr
 
333
              ? inet_ntoa (packet -> raw -> giaddr)
 
334
              : packet -> interface -> name);
 
335
 
 
336
        /* Set up the parts of the address that are in common. */
 
337
        to.sin_family = AF_INET;
 
338
#ifdef HAVE_SA_LEN
 
339
        to.sin_len = sizeof to;
 
340
#endif
 
341
        memset (to.sin_zero, 0, sizeof to.sin_zero);
 
342
 
 
343
        /* If this was gatewayed, send it back to the gateway... */
 
344
        if (raw.giaddr.s_addr) {
 
345
                to.sin_addr = raw.giaddr;
 
346
                to.sin_port = local_port;
 
347
 
 
348
                if (fallback_interface) {
 
349
                        result = send_packet (fallback_interface,
 
350
                                              (struct packet *)0,
 
351
                                              &raw, outgoing.packet_length,
 
352
                                              from, &to, &hto);
 
353
                        return;
 
354
                }
 
355
 
 
356
        /* If it comes from a client that already knows its address
 
357
           and is not requesting a broadcast response, and we can
 
358
           unicast to a client without using the ARP protocol, sent it
 
359
           directly to that client. */
 
360
        } else if (!(raw.flags & htons (BOOTP_BROADCAST)) &&
 
361
                   can_unicast_without_arp ()) {
 
362
                to.sin_addr = raw.yiaddr;
 
363
                to.sin_port = remote_port;
 
364
 
 
365
        /* Otherwise, broadcast it on the local network. */
 
366
        } else {
 
367
                to.sin_addr.s_addr = INADDR_BROADCAST;
 
368
                to.sin_port = remote_port; /* XXX */
 
369
        }
 
370
 
 
371
        errno = 0;
 
372
        result = send_packet (packet -> interface,
 
373
                              packet, &raw, outgoing.packet_length,
 
374
                              from, &to, &hto);
 
375
}