00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "dhcpd.h"
00031 #include <errno.h>
00032
00033 #if defined (TRACING)
00034 # define send_packet trace_packet_send
00035 #endif
00036
00037 void bootp (packet)
00038 struct packet *packet;
00039 {
00040 int result;
00041 struct host_decl *hp = (struct host_decl *)0;
00042 struct host_decl *host = (struct host_decl *)0;
00043 struct packet outgoing;
00044 struct dhcp_packet raw;
00045 struct sockaddr_in to;
00046 struct in_addr from;
00047 struct hardware hto;
00048 struct option_state *options = (struct option_state *)0;
00049 struct lease *lease = (struct lease *)0;
00050 unsigned i;
00051 struct data_string d1;
00052 struct option_cache *oc;
00053 char msgbuf [1024];
00054 int ignorep;
00055 int peer_has_leases = 0;
00056 int norelay = 0;
00057
00058 if (packet -> raw -> op != BOOTREQUEST)
00059 return;
00060
00061
00062
00063
00064 snprintf (msgbuf, sizeof msgbuf, "BOOTREQUEST from %s via %s",
00065 print_hw_addr (packet -> raw -> htype,
00066 packet -> raw -> hlen,
00067 packet -> raw -> chaddr),
00068 packet -> raw -> giaddr.s_addr
00069 ? inet_ntoa (packet -> raw -> giaddr)
00070 : packet -> interface -> name);
00071
00072 if ((norelay = locate_network (packet)) == 0) {
00073 log_info ("%s: network unknown", msgbuf);
00074 return;
00075 }
00076
00077 find_lease (&lease, packet, packet -> shared_network,
00078 0, 0, (struct lease *)0, MDL);
00079
00080 if (lease && lease->host)
00081 host_reference(&hp, lease->host, MDL);
00082
00083 if (!lease || ((lease->flags & STATIC_LEASE) == 0)) {
00084 struct host_decl *h;
00085
00086
00087
00088
00089
00090
00091 if (!hp)
00092 find_hosts_by_haddr(&hp, packet->raw->htype,
00093 packet->raw->chaddr,
00094 packet->raw->hlen, MDL);
00095
00096 for (h = hp; h; h = h -> n_ipaddr) {
00097 if (!h -> fixed_addr) {
00098 host_reference(&host, h, MDL);
00099 break;
00100 }
00101 }
00102
00103 if (hp)
00104 host_dereference(&hp, MDL);
00105
00106 if (host) {
00107 host_reference(&hp, host, MDL);
00108 host_dereference(&host, MDL);
00109 }
00110
00111
00112 if (!lease)
00113 allocate_lease (&lease, packet,
00114 packet -> shared_network -> pools,
00115 &peer_has_leases);
00116
00117 if (lease == NULL) {
00118 log_info("%s: BOOTP from dynamic client and no "
00119 "dynamic leases", msgbuf);
00120 goto out;
00121 }
00122
00123 #if defined(FAILOVER_PROTOCOL)
00124 if ((lease->pool != NULL) &&
00125 (lease->pool->failover_peer != NULL)) {
00126 dhcp_failover_state_t *peer;
00127
00128 peer = lease->pool->failover_peer;
00129
00130
00131
00132
00133
00134
00135 if ((peer->service_state == not_responding) ||
00136 (peer->service_state == service_startup)) {
00137 log_info("%s: not responding%s",
00138 msgbuf, peer->nrr);
00139 goto out;
00140 } else if((peer->service_state == cooperating) &&
00141 !load_balance_mine(packet, peer)) {
00142 log_info("%s: load balance to peer %s",
00143 msgbuf, peer->name);
00144 goto out;
00145 }
00146 }
00147 #endif
00148
00149 ack_lease (packet, lease, 0, 0, msgbuf, 0, hp);
00150 goto out;
00151 }
00152
00153
00154
00155 option_state_allocate (&options, MDL);
00156
00157
00158 execute_statements_in_scope (NULL, packet, lease, NULL,
00159 packet->options, options,
00160 &lease->scope, lease->subnet->group,
00161 NULL, NULL);
00162
00163
00164 for (i = packet -> class_count; i > 0; i--) {
00165 execute_statements_in_scope(NULL, packet, lease, NULL,
00166 packet->options, options,
00167 &lease->scope,
00168 packet->classes[i - 1]->group,
00169 lease->subnet->group, NULL);
00170 }
00171
00172
00173 if (hp != NULL) {
00174 execute_statements_in_scope (NULL, packet, lease, NULL,
00175 packet->options, options,
00176 &lease->scope, hp->group,
00177 lease->subnet->group, NULL);
00178 }
00179
00180
00181 if ((oc = lookup_option (&server_universe, options, SV_ALLOW_BOOTP)) &&
00182 !evaluate_boolean_option_cache (&ignorep, packet, lease,
00183 (struct client_state *)0,
00184 packet -> options, options,
00185 &lease -> scope, oc, MDL)) {
00186 if (!ignorep)
00187 log_info ("%s: bootp disallowed", msgbuf);
00188 goto out;
00189 }
00190
00191 if ((oc = lookup_option (&server_universe,
00192 options, SV_ALLOW_BOOTING)) &&
00193 !evaluate_boolean_option_cache (&ignorep, packet, lease,
00194 (struct client_state *)0,
00195 packet -> options, options,
00196 &lease -> scope, oc, MDL)) {
00197 if (!ignorep)
00198 log_info ("%s: booting disallowed", msgbuf);
00199 goto out;
00200 }
00201
00202
00203 memset (&outgoing, 0, sizeof outgoing);
00204 memset (&raw, 0, sizeof raw);
00205 outgoing.raw = &raw;
00206
00207
00208
00209 if (!packet -> options_valid &&
00210 !(evaluate_boolean_option_cache
00211 (&ignorep, packet, lease, (struct client_state *)0,
00212 packet -> options, options, &lease -> scope,
00213 lookup_option (&server_universe, options,
00214 SV_ALWAYS_REPLY_RFC1048), MDL))) {
00215 memcpy (outgoing.raw -> options,
00216 packet -> raw -> options, DHCP_MAX_OPTION_LEN);
00217 outgoing.packet_length = BOOTP_MIN_LEN;
00218 } else {
00219
00220
00221
00222
00223 oc = (struct option_cache *)0;
00224 i = DHO_SUBNET_MASK;
00225 if (!lookup_option (&dhcp_universe, options, i)) {
00226 if (option_cache_allocate (&oc, MDL)) {
00227 if (make_const_data
00228 (&oc -> expression,
00229 lease -> subnet -> netmask.iabuf,
00230 lease -> subnet -> netmask.len,
00231 0, 0, MDL)) {
00232 option_code_hash_lookup(&oc->option,
00233 dhcp_universe.code_hash,
00234 &i, 0, MDL);
00235 save_option (&dhcp_universe,
00236 options, oc);
00237 }
00238 option_cache_dereference (&oc, MDL);
00239 }
00240 }
00241
00242
00243
00244
00245
00246 outgoing.packet_length =
00247 cons_options (packet, outgoing.raw, lease,
00248 (struct client_state *)0, 0,
00249 packet -> options, options,
00250 &lease -> scope,
00251 0, 0, 1, (struct data_string *)0,
00252 (const char *)0);
00253 if (outgoing.packet_length < BOOTP_MIN_LEN)
00254 outgoing.packet_length = BOOTP_MIN_LEN;
00255 }
00256
00257
00258 raw.op = BOOTREPLY;
00259 raw.htype = packet -> raw -> htype;
00260 raw.hlen = packet -> raw -> hlen;
00261 memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
00262 raw.hops = packet -> raw -> hops;
00263 raw.xid = packet -> raw -> xid;
00264 raw.secs = packet -> raw -> secs;
00265 raw.flags = packet -> raw -> flags;
00266 raw.ciaddr = packet -> raw -> ciaddr;
00267
00268
00269 memcpy (&raw.yiaddr, lease->ip_addr.iabuf, 4);
00270
00271
00272
00273 if ((oc = lookup_option (&server_universe,
00274 options, SV_ALWAYS_BROADCAST)) &&
00275 evaluate_boolean_option_cache (&ignorep, packet, lease,
00276 (struct client_state *)0,
00277 packet -> options, options,
00278 &lease -> scope, oc, MDL))
00279 raw.flags |= htons (BOOTP_BROADCAST);
00280
00281
00282 memset (&d1, 0, sizeof d1);
00283 oc = lookup_option (&server_universe, options, SV_NEXT_SERVER);
00284 if (oc &&
00285 evaluate_option_cache (&d1, packet, lease,
00286 (struct client_state *)0,
00287 packet -> options, options,
00288 &lease -> scope, oc, MDL)) {
00289
00290 if (d1.len >= 4 && d1.data)
00291 memcpy (&raw.siaddr, d1.data, 4);
00292 data_string_forget (&d1, MDL);
00293 } else {
00294 if ((lease->subnet->shared_network->interface != NULL) &&
00295 lease->subnet->shared_network->interface->address_count)
00296 raw.siaddr =
00297 lease->subnet->shared_network->interface->addresses[0];
00298 else if (packet->interface->address_count)
00299 raw.siaddr = packet->interface->addresses[0];
00300 }
00301
00302 raw.giaddr = packet -> raw -> giaddr;
00303
00304
00305 oc = lookup_option (&server_universe, options, SV_FILENAME);
00306 if (oc &&
00307 evaluate_option_cache (&d1, packet, lease,
00308 (struct client_state *)0,
00309 packet -> options, options,
00310 &lease -> scope, oc, MDL)) {
00311 memcpy (raw.file, d1.data,
00312 d1.len > sizeof raw.file ? sizeof raw.file : d1.len);
00313 if (sizeof raw.file > d1.len)
00314 memset (&raw.file [d1.len],
00315 0, (sizeof raw.file) - d1.len);
00316 data_string_forget (&d1, MDL);
00317 } else
00318 memcpy (raw.file, packet -> raw -> file, sizeof raw.file);
00319
00320
00321 oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
00322 if (oc &&
00323 evaluate_option_cache (&d1, packet, lease,
00324 (struct client_state *)0,
00325 packet -> options, options,
00326 &lease -> scope, oc, MDL)) {
00327 memcpy (raw.sname, d1.data,
00328 d1.len > sizeof raw.sname ? sizeof raw.sname : d1.len);
00329 if (sizeof raw.sname > d1.len)
00330 memset (&raw.sname [d1.len],
00331 0, (sizeof raw.sname) - d1.len);
00332 data_string_forget (&d1, MDL);
00333 }
00334
00335
00336 execute_statements (NULL, packet, lease, NULL, packet->options,
00337 options, &lease->scope, lease->on_star.on_commit,
00338 NULL);
00339
00340
00341 option_state_dereference (&options, MDL);
00342
00343
00344 hto.hbuf [0] = packet -> raw -> htype;
00345 hto.hlen = packet -> raw -> hlen + 1;
00346 memcpy (&hto.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen);
00347
00348 if (packet->interface->address_count) {
00349 from = packet->interface->addresses[0];
00350 } else {
00351 log_error("%s: Interface %s appears to have no IPv4 "
00352 "addresses, and so dhcpd cannot select a source "
00353 "address.", msgbuf, packet->interface->name);
00354 goto out;
00355 }
00356
00357
00358 log_info("%s", msgbuf);
00359 log_info("BOOTREPLY for %s to %s (%s) via %s",
00360 piaddr(lease->ip_addr),
00361 ((hp != NULL) && (hp->name != NULL)) ? hp -> name : "unknown",
00362 print_hw_addr (packet->raw->htype,
00363 packet->raw->hlen,
00364 packet->raw->chaddr),
00365 packet->raw->giaddr.s_addr
00366 ? inet_ntoa (packet->raw->giaddr)
00367 : packet->interface->name);
00368
00369
00370 to.sin_family = AF_INET;
00371 #ifdef HAVE_SA_LEN
00372 to.sin_len = sizeof to;
00373 #endif
00374 memset (to.sin_zero, 0, sizeof to.sin_zero);
00375
00376
00377 if (raw.giaddr.s_addr) {
00378 to.sin_addr = raw.giaddr;
00379 to.sin_port = local_port;
00380
00381 if (fallback_interface) {
00382 result = send_packet (fallback_interface, NULL, &raw,
00383 outgoing.packet_length, from,
00384 &to, &hto);
00385 if (result < 0) {
00386 log_error ("%s:%d: Failed to send %d byte long "
00387 "packet over %s interface.", MDL,
00388 outgoing.packet_length,
00389 fallback_interface->name);
00390 }
00391
00392 goto out;
00393 }
00394 } else if (norelay == 2) {
00395 to.sin_addr = raw.ciaddr;
00396 to.sin_port = remote_port;
00397 if (fallback_interface) {
00398 result = send_packet (fallback_interface, NULL, &raw,
00399 outgoing.packet_length, from,
00400 &to, &hto);
00401 goto out;
00402 }
00403
00404
00405
00406
00407
00408 } else if (!(raw.flags & htons (BOOTP_BROADCAST)) &&
00409 can_unicast_without_arp (packet -> interface)) {
00410 to.sin_addr = raw.yiaddr;
00411 to.sin_port = remote_port;
00412
00413
00414 } else {
00415 to.sin_addr = limited_broadcast;
00416 to.sin_port = remote_port;
00417 }
00418
00419 errno = 0;
00420 result = send_packet(packet->interface, packet, &raw,
00421 outgoing.packet_length, from, &to, &hto);
00422 if (result < 0) {
00423 log_error ("%s:%d: Failed to send %d byte long packet over %s"
00424 " interface.", MDL, outgoing.packet_length,
00425 packet->interface->name);
00426 }
00427
00428 out:
00429
00430 if (options)
00431 option_state_dereference (&options, MDL);
00432 if (lease)
00433 lease_dereference (&lease, MDL);
00434 if (hp)
00435 host_dereference (&hp, MDL);
00436 if (host)
00437 host_dereference (&host, MDL);
00438 }