Coverage Report

Created: 2026-09-14 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dnsmasq/src/rfc2131.c
Line
Count
Source
1
/* dnsmasq is Copyright (c) 2000-2026 Simon Kelley
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 dated June, 1991, or
6
   (at your option) version 3 dated 29 June, 2007.
7
 
8
   This program is distributed in the hope that it will be useful,
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
10
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
   GNU General Public License for more details.
12
     
13
   You should have received a copy of the GNU General Public License
14
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
*/
16
17
#include "dnsmasq.h"
18
19
#ifdef HAVE_DHCP
20
21
0
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
22
0
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
23
24
#ifdef HAVE_SCRIPT
25
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
26
#endif
27
28
static int sanitise(unsigned char *opt, char *buf);
29
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
30
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
31
static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
32
static void option_put_string(struct dhcp_packet *mess, unsigned char *end, 
33
            int opt, const char *string, int null_term);
34
static struct in_addr option_addr(unsigned char *opt);
35
static unsigned int option_uint(unsigned char *opt, int offset, int size);
36
static void log_packet(char *type, void *addr, unsigned char *ext_mac, 
37
           int mac_len, char *interface, char *string, char *err, u32 xid);
38
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
39
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
40
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
41
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
42
static int in_list(unsigned char *list, int opt);
43
static unsigned char *free_space(struct dhcp_packet *mess, unsigned char *end, int opt, int len);
44
static void do_options(struct dhcp_context *context,
45
           struct dhcp_packet *mess,
46
           unsigned char *end,
47
           unsigned char *req_options,
48
           char *hostname, 
49
           char *domain,
50
           struct dhcp_netid *netid,
51
           struct in_addr subnet_addr, 
52
           unsigned char fqdn_flags,
53
           int null_term, int pxe_arch,
54
           unsigned char *uuid,
55
           int vendor_class_len,
56
           time_t now,
57
           unsigned int lease_time,
58
           unsigned short fuzz,
59
           const char *pxevendor,
60
           int leasequery);
61
62
63
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt); 
64
static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
65
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid, const char *pxevendor);
66
static int prune_vendor_opts(struct dhcp_netid *netid);
67
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
68
struct dhcp_boot *find_boot(struct dhcp_netid *netid);
69
static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe);
70
static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid);
71
static int is_pxe_client(struct dhcp_packet *mess, size_t sz, const char **pxe_vendor);
72
static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *context, int null_term);
73
static void handle_encap(struct dhcp_packet *mess, unsigned char *end, unsigned char *req_options, int null_term, struct dhcp_netid *tagif, int pxemode);
74
75
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
76
      size_t sz, time_t now, int unicast_dest, int loopback,
77
      int *is_inform, int pxe, struct in_addr fallback, time_t recvtime, struct in_addr leasequery_source)
78
0
{
79
0
  unsigned char *opt, *clid = NULL;
80
0
  struct dhcp_lease *ltmp, *lease = NULL;
81
0
  struct dhcp_vendor *vendor;
82
0
  struct dhcp_mac *mac;
83
0
  struct dhcp_netid_list *id_list;
84
0
  int clid_len = 0, ignore = 0, do_classes = 0, rapid_commit = 0, selecting = 0, pxearch = -1;
85
0
  const char *pxevendor = NULL;
86
0
  struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
87
0
  unsigned char *end = (unsigned char *)(mess + 1); 
88
0
  unsigned char *real_end = (unsigned char *)(mess + 1); 
89
0
  char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL, *domain = NULL;
90
0
  int hostname_auth = 0, borken_opt = 0;
91
0
  unsigned char *req_options = NULL;
92
0
  char *message = NULL;
93
0
  unsigned int time;
94
0
  struct dhcp_config *config;
95
0
  struct dhcp_netid *netid, *tagif_netid;
96
0
  struct in_addr subnet_addr, override;
97
0
  unsigned short fuzz = 0;
98
0
  unsigned int mess_type = 0;
99
0
  unsigned char fqdn_flags = 0;
100
0
  unsigned char *agent_id = NULL, *uuid = NULL;
101
0
  unsigned char *emac = NULL;
102
0
  int vendor_class_len = 0, emac_len = 0;
103
0
  struct dhcp_netid known_id, iface_id, cpewan_id;
104
0
  struct dhcp_opt *o;
105
0
  unsigned char pxe_uuid[17];
106
0
  unsigned char *oui = NULL, *serial = NULL;
107
0
#ifdef HAVE_SCRIPT
108
0
  unsigned char *class = NULL;
109
0
#endif
110
111
0
  subnet_addr.s_addr = override.s_addr = 0;
112
          
113
  /* set tag with name == interface */
114
0
  iface_id.net = iface_name;
115
0
  iface_id.next = NULL;
116
0
  netid = &iface_id; 
117
  
118
0
  if (mess->op != BOOTREQUEST || mess->hlen > DHCP_CHADDR_MAX)
119
0
    return 0;
120
   
121
0
  if (mess->htype == 0 && mess->hlen != 0)
122
0
    return 0;
123
124
  /* check for DHCP rather than BOOTP */
125
0
  if ((opt = option_find(mess, sz, OPTION_MESSAGE_TYPE, 1)))
126
0
    {
127
0
      u32 cookie = htonl(DHCP_COOKIE);
128
      
129
      /* only insist on a cookie for DHCP. */
130
0
      if (memcmp(mess->options, &cookie, sizeof(u32)) != 0)
131
0
  return 0;
132
      
133
0
      mess_type = option_uint(opt, 0, 1);
134
      
135
      /* two things to note here: expand_buf may move the packet,
136
   so reassign mess from daemon->packet. Also, the size
137
   sent includes the IP and UDP headers, hence the magic "-28" */
138
0
      if ((opt = option_find(mess, sz, OPTION_MAXMESSAGE, 2)))
139
0
  {
140
0
    size_t size = (size_t)option_uint(opt, 0, 2) - 28;
141
    
142
0
    if (size > DHCP_PACKET_MAX)
143
0
      size = DHCP_PACKET_MAX;
144
0
    else if (size < sizeof(struct dhcp_packet))
145
0
      size = sizeof(struct dhcp_packet);
146
    
147
0
    if (expand_buf(&daemon->dhcp_packet, size))
148
0
      {
149
0
        mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
150
0
        real_end = end = ((unsigned char *)mess) + size;
151
0
      }
152
0
  }
153
154
      /* Some buggy clients set ciaddr when they shouldn't, so clear that here since
155
   it can affect the context-determination code. */
156
0
      if ((option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ) || mess_type == DHCPDISCOVER))
157
0
  mess->ciaddr.s_addr = 0;
158
159
      /* search for device identity from CPEWAN devices, we pass this through to the script */
160
0
      if ((opt = option_find(mess, sz, OPTION_VENDOR_IDENT_OPT, 5)))
161
0
  {
162
0
    unsigned  int elen, offset, len = option_len(opt);
163
    
164
0
    for (offset = 0; offset < (len - 5); offset += elen + 5)
165
0
      {
166
0
        elen = option_uint(opt, offset + 4 , 1);
167
0
        if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA && offset + elen + 5 <= len)
168
0
    {
169
0
      unsigned char *x = option_ptr(opt, offset + 5);
170
0
      unsigned char *y = option_ptr(opt, offset + elen + 5);
171
0
      oui = option_find1(x, y, 1, 1);
172
0
      serial = option_find1(x, y, 2, 1);
173
0
#ifdef HAVE_SCRIPT
174
0
      class = option_find1(x, y, 3, 1);     
175
0
#endif
176
      /* If TR069-id is present set the tag "cpewan-id" to facilitate echoing 
177
         the gateway id back. Note that the device class is optional */
178
0
      if (oui && serial)
179
0
        {
180
0
          cpewan_id.net = "cpewan-id";
181
0
          cpewan_id.next = netid;
182
0
          netid = &cpewan_id;
183
0
        }
184
0
      break;
185
0
    }
186
0
      }
187
0
  }
188
      
189
0
      if (mess_type != DHCPLEASEQUERY && (opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
190
0
  {
191
    /* Any agent-id needs to be copied back out, verbatim, as the last option
192
       in the packet. Here, we shift it to the very end of the buffer, if it doesn't
193
       get overwritten, then it will be shuffled back at the end of processing.
194
       Note that the incoming options must not be overwritten here, so there has to 
195
       be enough free space at the end of the packet to copy the option. */
196
0
    unsigned char *sopt;
197
0
    unsigned int total = option_len(opt) + 2;
198
0
    unsigned char *last_opt = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + sz,
199
0
             OPTION_END, 0);
200
0
    if (last_opt && last_opt < end - total)
201
0
      {
202
0
        end -= total;
203
0
        agent_id = end;
204
0
        memcpy(agent_id, opt, total);
205
0
      }
206
207
    /* look for RFC5010 flags sub-option */
208
0
    if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_FLAGS, INADDRSZ)))
209
0
      unicast_dest = !!(option_uint(opt, 0, 1) & 0x80);
210
        
211
    /* look for RFC3527 Link selection sub-option */
212
0
    if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBNET_SELECT, INADDRSZ)))
213
0
      subnet_addr = option_addr(sopt);
214
215
    /* look for RFC5107 server-identifier-override */
216
0
    if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SERVER_OR, INADDRSZ)))
217
0
      override = option_addr(sopt);
218
    
219
    /* if a circuit-id or remote-is option is provided, exact-match to options. */
220
0
    for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
221
0
      {
222
0
        int search;
223
        
224
0
        if (vendor->match_type == MATCH_CIRCUIT)
225
0
    search = SUBOPT_CIRCUIT_ID;
226
0
        else if (vendor->match_type == MATCH_REMOTE)
227
0
    search = SUBOPT_REMOTE_ID;
228
0
        else if (vendor->match_type == MATCH_SUBSCRIBER)
229
0
    search = SUBOPT_SUBSCR_ID;
230
0
        else 
231
0
    continue;
232
        
233
0
        if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), search, 1)) &&
234
0
      vendor->len == option_len(sopt) &&
235
0
      memcmp(option_ptr(sopt, 0), vendor->data, vendor->len) == 0)
236
0
    {
237
0
      vendor->netid.next = netid;
238
0
      netid = &vendor->netid;
239
0
    } 
240
0
      }
241
0
  }
242
      
243
      /* Check for RFC3011 subnet selector - only if RFC3527 one not present */
244
0
      if (subnet_addr.s_addr == 0 && (opt = option_find(mess, sz, OPTION_SUBNET_SELECT, INADDRSZ)))
245
0
  subnet_addr = option_addr(opt);
246
      
247
      /* If there is no client identifier option, use the hardware address */
248
0
      if (!option_bool(OPT_IGNORE_CLID) && (opt = option_find(mess, sz, OPTION_CLIENT_ID, 1)))
249
0
  {
250
0
    clid_len = option_len(opt);
251
0
    clid = option_ptr(opt, 0);
252
0
  }
253
254
      /* do we have a lease in store? */
255
0
      lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, clid, clid_len);
256
257
      /* If this request is missing a clid, but we've seen one before, 
258
   use it again for option matching etc. */
259
0
      if (lease && !clid && lease->clid)
260
0
  {
261
0
    clid_len = lease->clid_len;
262
0
    clid = lease->clid;
263
0
  }
264
265
      /* find mac to use for logging and hashing */
266
0
      emac = extended_hwaddr(mess->htype, mess->hlen, mess->chaddr, clid_len, clid, &emac_len);
267
0
    }
268
  
269
0
  for (mac = daemon->dhcp_macs; mac; mac = mac->next)
270
0
    if (mac->hwaddr_len == mess->hlen &&
271
0
  (mac->hwaddr_type == mess->htype || mac->hwaddr_type == 0) &&
272
0
  memcmp_masked(mac->hwaddr, mess->chaddr, mess->hlen, mac->mask))
273
0
      {
274
0
  mac->netid.next = netid;
275
0
  netid = &mac->netid;
276
0
      }
277
  
278
  /* Determine network for this packet. Our caller will have already linked all the 
279
     contexts which match the addresses of the receiving interface but if the 
280
     machine has an address already, or came via a relay, or we have a subnet selector, 
281
     we search again. If we don't have have a giaddr or explicit subnet selector, 
282
     use the ciaddr. This is necessary because a  machine which got a lease via a 
283
     relay won't use the relay to renew. If matching a ciaddr fails but we have a context 
284
     from the physical network, continue using that to allow correct DHCPNAK generation later. */
285
0
  if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr)
286
0
    {
287
0
      struct dhcp_context *context_tmp, *context_new = NULL;
288
0
      struct shared_network *share = NULL;
289
0
      struct in_addr addr;
290
0
      int force = 0, via_relay = 0;
291
      
292
0
      if (subnet_addr.s_addr)
293
0
  {
294
0
    addr = subnet_addr;
295
0
    force = 1;
296
0
    if (mess->giaddr.s_addr)
297
0
      via_relay = 1;
298
0
  }
299
0
      else if (mess->giaddr.s_addr)
300
0
  {
301
0
    addr = mess->giaddr;
302
0
    force = 1;
303
0
    via_relay = 1;
304
0
  }
305
0
      else
306
0
  {
307
    /* If ciaddr is in the hardware derived set of contexts, leave that unchanged */
308
0
    addr = mess->ciaddr;
309
0
    for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
310
0
      if (context_tmp->netmask.s_addr && 
311
0
    is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
312
0
    is_same_net(addr, context_tmp->end, context_tmp->netmask))
313
0
        {
314
0
    context_new = context;
315
0
    break;
316
0
        }
317
0
  } 
318
    
319
0
      if (!context_new)
320
0
  {
321
0
    for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
322
0
      {
323
0
        struct in_addr netmask = context_tmp->netmask;
324
        
325
        /* guess the netmask for relayed networks */
326
0
        if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0)
327
0
    {
328
0
      if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr)))
329
0
        netmask.s_addr = htonl(0xff000000);
330
0
      else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr)))
331
0
        netmask.s_addr = htonl(0xffff0000);
332
0
      else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr)))
333
0
        netmask.s_addr = htonl(0xffffff00); 
334
0
    }
335
336
        /* check to see is a context is OK because of a shared address on
337
     the relayed subnet. */
338
0
        if (via_relay)
339
0
    for (share = daemon->shared_networks; share; share = share->next)
340
0
      {
341
0
#ifdef HAVE_DHCP6
342
0
        if (share->shared_addr.s_addr == 0)
343
0
          continue;
344
0
#endif
345
0
        if (share->if_index != 0 ||
346
0
      share->match_addr.s_addr != mess->giaddr.s_addr)
347
0
          continue;
348
        
349
0
        if (netmask.s_addr != 0  && 
350
0
      is_same_net(share->shared_addr, context_tmp->start, netmask) &&
351
0
      is_same_net(share->shared_addr, context_tmp->end, netmask))
352
0
          break;
353
0
      }
354
        
355
        /* This section fills in context mainly when a client which is on a remote (relayed)
356
     network renews a lease without using the relay, after dnsmasq has restarted. */
357
0
        if (share ||
358
0
      (netmask.s_addr != 0  && 
359
0
       is_same_net(addr, context_tmp->start, netmask) &&
360
0
       is_same_net(addr, context_tmp->end, netmask)))
361
0
    {
362
0
      context_tmp->netmask = netmask;
363
0
      if (context_tmp->local.s_addr == 0)
364
0
        context_tmp->local = fallback;
365
0
      if (context_tmp->router.s_addr == 0 && !share)
366
0
        {
367
0
          if (override.s_addr)
368
0
      context_tmp->router = override;
369
0
          else
370
0
      context_tmp->router = mess->giaddr;
371
0
        }
372
      
373
      /* fill in missing broadcast addresses for relayed ranges */
374
0
      if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )
375
0
        context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr;
376
      
377
0
      context_tmp->current = context_new;
378
0
      context_new = context_tmp;
379
0
    }
380
        
381
0
      }
382
0
  }
383
    
384
0
      if (context_new || force)
385
0
  context = context_new; 
386
0
    }
387
  
388
0
  if (mess_type != DHCPLEASEQUERY)
389
0
    {
390
0
      if  (!context)
391
0
  {
392
0
    const char *via;
393
0
    if (subnet_addr.s_addr)
394
0
      {
395
0
        via = _("with subnet selector");
396
0
        inet_ntop(AF_INET, &subnet_addr, daemon->addrbuff, ADDRSTRLEN);
397
0
      }
398
0
    else
399
0
      {
400
0
        via = _("via");
401
0
        if (mess->giaddr.s_addr)
402
0
    inet_ntop(AF_INET, &mess->giaddr, daemon->addrbuff, ADDRSTRLEN);
403
0
        else
404
0
    safe_strncpy(daemon->addrbuff, iface_name, ADDRSTRLEN);
405
0
      }
406
0
    my_syslog(MS_DHCP | LOG_WARNING, _("no address range available for DHCP request %s %s"),
407
0
        via, daemon->addrbuff);
408
0
    return 0;
409
0
  }
410
      
411
0
      if (option_bool(OPT_LOG_OPTS))
412
0
  {
413
0
    struct dhcp_context *context_tmp;
414
0
    for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
415
0
      {
416
0
        inet_ntop(AF_INET, &context_tmp->start, daemon->namebuff, MAXDNAMESTR);
417
0
        if (context_tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
418
0
    {
419
0
      inet_ntop(AF_INET, &context_tmp->netmask, daemon->addrbuff, ADDRSTRLEN);
420
0
      my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP subnet: %s/%s"),
421
0
          ntohl(mess->xid), daemon->namebuff, daemon->addrbuff);
422
0
    }
423
0
        else
424
0
    {
425
0
      inet_ntop(AF_INET, &context_tmp->end, daemon->addrbuff, ADDRSTRLEN);
426
0
      my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"),
427
0
          ntohl(mess->xid), daemon->namebuff, daemon->addrbuff);
428
0
    }
429
0
      }
430
0
  }
431
0
    }
432
  
433
  /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
434
     Otherwise assume the option is an array, and look for a matching element. 
435
     If no data given, existence of the option is enough. This code handles 
436
     rfc3925 V-I classes too. */
437
0
  for (o = daemon->dhcp_match; o; o = o->next)
438
0
    {
439
0
      unsigned int len, elen, match = 0;
440
0
      size_t offset, o2;
441
442
0
      if (o->flags & DHOPT_RFC3925)
443
0
  {
444
0
    if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
445
0
      continue;
446
    
447
0
    for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
448
0
      {
449
0
        len = option_uint(opt, offset + 4 , 1);
450
        /* Need to take care that bad data can't run us off the end of the packet */
451
0
        if ((offset + len + 5 <= (unsigned)(option_len(opt))) &&
452
0
      (option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
453
0
    for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
454
0
      { 
455
0
        elen = option_uint(opt, o2, 1);
456
0
        if ((o2 + elen + 1 <= (unsigned)option_len(opt)) &&
457
0
      (match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
458
0
          break;
459
0
      }
460
0
        if (match) 
461
0
    break;
462
0
      }   
463
0
  }
464
0
      else
465
0
  {
466
0
    if (!(opt = option_find(mess, sz, o->opt, 1)))
467
0
      continue;
468
    
469
0
    match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
470
0
  } 
471
472
0
      if (match)
473
0
  {
474
0
    o->netid->next = netid;
475
0
    netid = o->netid;
476
0
  }
477
0
    }
478
  
479
  /* user-class options are, according to RFC3004, supposed to contain
480
     a set of counted strings. Here we check that this is so (by seeing
481
     if the counts are consistent with the overall option length) and if
482
     so zero the counts so that we don't get spurious matches between 
483
     the vendor string and the counts. If the lengths don't add up, we
484
     assume that the option is a single string and non RFC3004 compliant 
485
     and just do the substring match. dhclient provides these broken options.
486
     The code, later, which sends user-class data to the lease-change script
487
     relies on the transformation done here.
488
  */
489
490
0
  if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
491
0
    {
492
0
      unsigned char *ucp = option_ptr(opt, 0);
493
0
      int tmp, j;
494
0
      for (j = 0; j < option_len(opt); j += ucp[j] + 1);
495
0
      if (j == option_len(opt))
496
0
  for (j = 0; j < option_len(opt); j = tmp)
497
0
    {
498
0
      tmp = j + ucp[j] + 1;
499
0
      ucp[j] = 0;
500
0
    }
501
0
    }
502
    
503
0
  for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
504
0
    {
505
0
      int mopt;
506
      
507
0
      if (vendor->match_type == MATCH_VENDOR)
508
0
  mopt = OPTION_VENDOR_ID;
509
0
      else if (vendor->match_type == MATCH_USER)
510
0
  mopt = OPTION_USER_CLASS; 
511
0
      else
512
0
  continue;
513
514
0
      if ((opt = option_find(mess, sz, mopt, 1)))
515
0
  {
516
0
    int i;
517
0
    for (i = 0; i <= (option_len(opt) - vendor->len); i++)
518
0
      if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
519
0
        {
520
0
    vendor->netid.next = netid;
521
0
    netid = &vendor->netid;
522
0
    break;
523
0
        }
524
0
  }
525
0
    }
526
527
  /* mark vendor-encapsulated options which match the client-supplied vendor class,
528
     save client-supplied vendor class */
529
0
  if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
530
0
    {
531
0
      memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
532
0
      vendor_class_len = option_len(opt);
533
0
    }
534
0
  match_vendor_opts(opt, daemon->dhcp_opts);
535
  
536
0
  if (option_bool(OPT_LOG_OPTS))
537
0
    {
538
0
      if (sanitise(opt, daemon->namebuff))
539
0
  my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
540
0
      if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
541
0
  my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
542
0
    }
543
544
0
  mess->op = BOOTREPLY;
545
  
546
0
  config = find_config(daemon->dhcp_conf, context, clid, clid_len, 
547
0
           mess->chaddr, mess->hlen, mess->htype, NULL, run_tag_if(netid));
548
549
  /* set "known" tag for known hosts */
550
0
  if (config)
551
0
    {
552
0
      known_id.net = "known";
553
0
      known_id.next = netid;
554
0
      netid = &known_id;
555
0
    }
556
0
  else if (find_config(daemon->dhcp_conf, NULL, clid, clid_len, 
557
0
           mess->chaddr, mess->hlen, mess->htype, NULL, run_tag_if(netid)))
558
0
    {
559
0
      known_id.net = "known-othernet";
560
0
      known_id.next = netid;
561
0
      netid = &known_id;
562
0
    }
563
  
564
0
  if (mess_type == 0 && !pxe)
565
0
    {
566
      /* BOOTP request */
567
0
      struct dhcp_netid id, bootp_id;
568
0
      struct in_addr *logaddr = NULL;
569
570
      /* must have a MAC addr for bootp */
571
0
      if (mess->htype == 0 || mess->hlen == 0 || (context->flags & CONTEXT_PROXY))
572
0
  return 0;
573
      
574
0
      if (have_config(config, CONFIG_DISABLE))
575
0
  message = _("disabled");
576
577
0
      end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
578
            
579
0
      if (have_config(config, CONFIG_NAME))
580
0
  {
581
0
    hostname = config->hostname;
582
0
    domain = config->domain;
583
0
  }
584
585
0
      if (config)
586
0
  {
587
0
    struct dhcp_netid_list *list;
588
589
0
    for (list = config->netid; list; list = list->next)
590
0
      {
591
0
        list->list->next = netid;
592
0
        netid = list->list;
593
0
      }
594
0
  }
595
596
      /* Match incoming filename field as a netid. */
597
0
      if (mess->file[0])
598
0
  {
599
0
    memcpy(daemon->dhcp_buff2, mess->file, sizeof(mess->file));
600
0
    daemon->dhcp_buff2[sizeof(mess->file)] = 0; /* ensure zero term. */
601
0
    id.net = (char *)daemon->dhcp_buff2;
602
0
    id.next = netid;
603
0
    netid = &id;
604
0
  }
605
606
      /* Add "bootp" as a tag to allow different options, address ranges etc
607
   for BOOTP clients */
608
0
      bootp_id.net = "bootp";
609
0
      bootp_id.next = netid;
610
0
      netid = &bootp_id;
611
      
612
0
      tagif_netid = run_tag_if(netid);
613
614
0
      for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
615
0
  if (match_netid(id_list->list, tagif_netid, 0))
616
0
    message = _("ignored");
617
      
618
0
      if (!message)
619
0
  {
620
0
    int nailed = 0;
621
622
0
    if (have_config(config, CONFIG_ADDR))
623
0
      {
624
0
        nailed = 1;
625
0
        logaddr = &config->addr;
626
0
        mess->yiaddr = config->addr;
627
0
        if ((lease = lease_find_by_addr(config->addr)) &&
628
0
      (lease->hwaddr_len != mess->hlen ||
629
0
       lease->hwaddr_type != mess->htype ||
630
0
       memcmp(lease->hwaddr, mess->chaddr, lease->hwaddr_len) != 0))
631
0
    message = _("address in use");
632
0
      }
633
0
    else
634
0
      {
635
0
        if (!(lease = lease_find_by_client(mess->chaddr, mess->hlen, mess->htype, NULL, 0)) ||
636
0
      !address_available(context, lease->addr, tagif_netid))
637
0
    {
638
0
       if (lease)
639
0
         {
640
           /* lease exists, wrong network. */
641
0
           lease_prune(lease, now);
642
0
           lease = NULL;
643
0
         }
644
0
       if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, tagif_netid, now, loopback))
645
0
         message = _("no address available");
646
0
    }
647
0
        else
648
0
    mess->yiaddr = lease->addr;
649
0
      }
650
    
651
0
    if (!message && !(context = narrow_context(context, mess->yiaddr, netid)))
652
0
      message = _("wrong network");
653
0
    else if (context->netid.net)
654
0
      {
655
0
        context->netid.next = netid;
656
0
        tagif_netid = run_tag_if(&context->netid);
657
0
      }
658
659
0
    log_tags(tagif_netid, ntohl(mess->xid));
660
      
661
0
    if (!message && !nailed)
662
0
      {
663
0
        for (id_list = daemon->bootp_dynamic; id_list; id_list = id_list->next)
664
0
    if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
665
0
      break;
666
0
        if (!id_list)
667
0
    message = _("no address configured");
668
0
      }
669
670
0
    if (!message && 
671
0
        !lease && 
672
0
        (!(lease = lease4_allocate(mess->yiaddr))))
673
0
      message = _("no leases left");
674
    
675
0
    if (!message)
676
0
      {
677
0
        logaddr = &mess->yiaddr;
678
    
679
0
        lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0, now, 1);
680
0
        if (hostname)
681
0
    lease_set_hostname(lease, hostname, 1, get_domain(lease->addr), domain); 
682
        /* infinite lease unless nailed in dhcp-host line. */
683
0
        lease_set_expires(lease,  
684
0
        have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff, 
685
0
        now); 
686
0
        lease_set_interface(lease, int_index, now);
687
        
688
0
        clear_packet(mess, end);
689
0
        do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr), 
690
0
       netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0, NULL, 0);
691
0
      }
692
0
  }
693
      
694
0
      daemon->metrics[METRIC_BOOTP]++;
695
0
      log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, NULL, message, mess->xid);
696
      
697
0
      return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
698
0
    }
699
      
700
0
  if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 3)))
701
0
    {
702
      /* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
703
0
      int len = option_len(opt);
704
0
      char *pq = daemon->dhcp_buff;
705
0
      unsigned char *pp, *op = option_ptr(opt, 0);
706
      
707
0
      fqdn_flags = *op;
708
0
      len -= 3;
709
0
      op += 3;
710
0
      pp = op;
711
      
712
      /* NB, the following always sets at least one bit */
713
0
      if (option_bool(OPT_FQDN_UPDATE))
714
0
  {
715
0
    if (fqdn_flags & 0x01)
716
0
      {
717
0
        fqdn_flags |= 0x02; /* set O */
718
0
        fqdn_flags &= ~0x01; /* clear S */
719
0
      }
720
0
    fqdn_flags |= 0x08; /* set N */
721
0
  }
722
0
      else 
723
0
  {
724
0
    if (!(fqdn_flags & 0x01))
725
0
      fqdn_flags |= 0x03; /* set S and O */
726
0
    fqdn_flags &= ~0x08; /* clear N */
727
0
  }
728
      
729
0
      if (fqdn_flags & 0x04)
730
0
  while (*op != 0 && ((op + (*op)) - pp) < len)
731
0
    {
732
0
      memcpy(pq, op+1, *op);
733
0
      pq += *op;
734
0
      op += (*op)+1;
735
0
      *(pq++) = '.';
736
0
    }
737
0
      else
738
0
  {
739
0
    memcpy(pq, op, len);
740
0
    if (len > 0 && op[len-1] == 0)
741
0
      borken_opt = 1;
742
0
    pq += len + 1;
743
0
  }
744
      
745
0
      if (pq != daemon->dhcp_buff)
746
0
  pq--;
747
      
748
0
      *pq = 0;
749
      
750
0
      if (legal_hostname(daemon->dhcp_buff))
751
0
  offer_hostname = client_hostname = daemon->dhcp_buff;
752
0
    }
753
0
  else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
754
0
    {
755
0
      int len = option_len(opt);
756
0
      memcpy(daemon->dhcp_buff, option_ptr(opt, 0), len);
757
      /* Microsoft clients are broken, and need zero-terminated strings
758
   in options. We detect this state here, and do the same in
759
   any options we send */
760
0
      if (len > 0 && daemon->dhcp_buff[len-1] == 0)
761
0
  borken_opt = 1;
762
0
      else
763
0
  daemon->dhcp_buff[len] = 0;
764
0
      if (legal_hostname(daemon->dhcp_buff))
765
0
  client_hostname = daemon->dhcp_buff;
766
0
    }
767
768
0
  if (client_hostname)
769
0
    {
770
0
      struct dhcp_match_name *m;
771
0
      size_t nl = strlen(client_hostname);
772
      
773
0
      if (option_bool(OPT_LOG_OPTS))
774
0
  my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname);
775
0
      for (m = daemon->dhcp_name_match; m; m = m->next)
776
0
  {
777
0
    size_t ml = strlen(m->name);
778
0
    char save = 0;
779
    
780
0
    if (nl < ml)
781
0
      continue;
782
0
    if (nl > ml)
783
0
      {
784
0
        save = client_hostname[ml];
785
0
        client_hostname[ml] = 0;
786
0
      }
787
    
788
0
    if (hostname_isequal(client_hostname, m->name) &&
789
0
        (save == 0 || m->wildcard))
790
0
      {
791
0
        m->netid->next = netid;
792
0
        netid = m->netid;
793
0
      }
794
    
795
0
    if (save != 0)
796
0
      client_hostname[ml] = save;
797
0
  }
798
0
    }
799
  
800
0
  if (have_config(config, CONFIG_NAME))
801
0
    {
802
0
      hostname = config->hostname;
803
0
      domain = config->domain;
804
0
      hostname_auth = 1;
805
      /* be careful not to send an OFFER with a hostname not matching the DISCOVER. */
806
0
      if (fqdn_flags != 0 || !client_hostname || hostname_isequal(hostname, client_hostname))
807
0
        offer_hostname = hostname;
808
0
    }
809
0
  else if (client_hostname)
810
0
    {
811
0
      domain = strip_hostname(client_hostname);
812
      
813
0
      if (strlen(client_hostname) != 0)
814
0
  {
815
0
    hostname = client_hostname;
816
    
817
0
    if (!config)
818
0
      {
819
        /* Search again now we have a hostname. 
820
     Only accept configs without CLID and HWADDR here, (they won't match)
821
     to avoid impersonation by name. */
822
0
        struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
823
0
                mess->chaddr, mess->hlen, 
824
0
                mess->htype, hostname, run_tag_if(netid));
825
0
        if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
826
0
    {
827
0
      config = new;
828
      /* set "known" tag for known hosts */
829
0
      known_id.net = "known";
830
0
      known_id.next = netid;
831
0
      netid = &known_id;
832
0
    }
833
0
      }
834
0
  }
835
0
    }
836
837
0
  if (mess_type != DHCPLEASEQUERY && config)
838
0
    {
839
0
      struct dhcp_netid_list *list;
840
      
841
0
      for (list = config->netid; list; list = list->next)
842
0
  {
843
0
    list->list->next = netid;
844
0
    netid = list->list;
845
0
  }
846
0
    }
847
  
848
0
  tagif_netid = run_tag_if(netid);
849
  
850
  /* if all the netids in the ignore list are present, ignore this client */
851
0
  for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
852
0
    if (match_netid(id_list->list, tagif_netid, 0))
853
0
      ignore = 1;
854
855
  /* If configured, we can override the server-id to be the address of the relay, 
856
     so that all traffic goes via the relay and can pick up agent-id info. This can be
857
     configured for all relays, or by address. */
858
0
  if (daemon->override && mess->giaddr.s_addr != 0 && override.s_addr == 0)
859
0
    {
860
0
      if (!daemon->override_relays)
861
0
  override = mess->giaddr;
862
0
      else
863
0
  {
864
0
    struct addr_list *l;
865
0
    for (l = daemon->override_relays; l; l = l->next)
866
0
      if (l->addr.s_addr == mess->giaddr.s_addr)
867
0
        break;
868
0
    if (l)
869
0
      override = mess->giaddr;
870
0
  }
871
0
    }
872
873
  /* Can have setting to ignore the client ID for a particular MAC address or hostname */
874
0
  if (have_config(config, CONFIG_NOCLID))
875
0
    clid = NULL;
876
          
877
  /* Check if client is PXE client. */
878
0
  if (mess_type != DHCPLEASEQUERY &&
879
0
      daemon->enable_pxe &&
880
0
      is_pxe_client(mess, sz, &pxevendor))
881
0
    {
882
0
      if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
883
0
  {
884
0
    memcpy(pxe_uuid, option_ptr(opt, 0), 17);
885
0
    uuid = pxe_uuid;
886
0
  }
887
888
      /* Check if this is really a PXE bootserver request, and handle specially if so. */
889
0
      if ((mess_type == DHCPREQUEST || mess_type == DHCPINFORM) &&
890
0
    (opt = option_find(mess, sz, OPTION_VENDOR_CLASS_OPT, 1)) &&
891
0
    (opt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_PXE_BOOT_ITEM, 4)))
892
0
  {
893
0
    struct pxe_service *service;
894
0
    int type = option_uint(opt, 0, 2);
895
0
    int layer = option_uint(opt, 2, 2);
896
0
    unsigned char save71[4];
897
0
    struct dhcp_opt opt71;
898
899
0
    if (ignore)
900
0
      return 0;
901
902
0
    if (layer & 0x8000)
903
0
      {
904
0
        my_syslog(MS_DHCP | LOG_ERR, _("PXE BIS not supported"));
905
0
        return 0;
906
0
      }
907
908
0
    memcpy(save71, option_ptr(opt, 0), 4);
909
    
910
0
    for (service = daemon->pxe_services; service; service = service->next)
911
0
      if (service->type == type)
912
0
        break;
913
    
914
0
    for (; context; context = context->current)
915
0
      if (match_netid(context->filter, tagif_netid, 1) &&
916
0
    is_same_net(mess->ciaddr, context->start, context->netmask))
917
0
        break;
918
    
919
0
    if (!service || !service->basename || !context)
920
0
      return 0;
921
        
922
0
    clear_packet(mess, end);
923
    
924
0
    mess->yiaddr = mess->ciaddr;
925
0
    mess->ciaddr.s_addr = 0;
926
0
    if (service->sname)
927
0
      mess->siaddr = a_record_from_hosts(service->sname, now);
928
0
    else if (service->server.s_addr != 0)
929
0
      mess->siaddr = service->server; 
930
0
    else
931
0
      mess->siaddr = context->local; 
932
    
933
0
    if (strchr(service->basename, '.'))
934
0
      snprintf((char *)mess->file, sizeof(mess->file),
935
0
    "%s", service->basename);
936
0
    else
937
0
      snprintf((char *)mess->file, sizeof(mess->file),
938
0
    "%s.%d", service->basename, layer);
939
    
940
0
    option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
941
0
    option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
942
0
    pxe_misc(mess, end, uuid, pxevendor);
943
    
944
0
    prune_vendor_opts(tagif_netid);
945
0
    opt71.val = save71;
946
0
    opt71.opt = SUBOPT_PXE_BOOT_ITEM;
947
0
    opt71.len = 4;
948
0
    opt71.flags = DHOPT_VENDOR_MATCH;
949
0
    opt71.netid = NULL;
950
0
    opt71.next = daemon->dhcp_opts;
951
0
    do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
952
    
953
0
    daemon->metrics[METRIC_PXE]++;
954
0
    log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, NULL, mess->xid);
955
0
    log_tags(tagif_netid, ntohl(mess->xid));
956
0
    return dhcp_packet_size(mess, agent_id, real_end);   
957
0
  }
958
      
959
0
      if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
960
0
  {
961
0
    pxearch = option_uint(opt, 0, 2);
962
963
    /* proxy DHCP here. */
964
0
    if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)))
965
0
      {
966
0
        struct dhcp_context *tmp;
967
0
        int workaround = 0;
968
        
969
0
        for (tmp = context; tmp; tmp = tmp->current)
970
0
    if ((tmp->flags & CONTEXT_PROXY) &&
971
0
        match_netid(tmp->filter, tagif_netid, 1))
972
0
      break;
973
        
974
0
        if (tmp)
975
0
    {
976
0
      struct dhcp_boot *boot;
977
0
      int redirect4011 = 0;
978
0
      struct dhcp_opt *option;
979
980
      /* OK only dhcp-option-pxe options. */
981
0
      tagif_netid = option_filter(netid, tmp->netid.net ? &tmp->netid : NULL, daemon->dhcp_opts, 2);
982
0
      boot = find_boot(tagif_netid);
983
      
984
0
      mess->yiaddr.s_addr = 0;
985
0
      if  (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
986
0
        {
987
0
          mess->ciaddr.s_addr = 0;
988
0
          mess->flags |= htons(0x8000); /* broadcast */
989
0
        }
990
      
991
0
      clear_packet(mess, end);
992
      
993
      /* Redirect EFI clients to port 4011 */
994
0
      if (pxearch >= 6)
995
0
        {
996
0
          redirect4011 = 1;
997
0
          mess->siaddr = tmp->local;
998
0
        }
999
      
1000
      /* Returns true if only one matching service is available. On port 4011, 
1001
         it also inserts the boot file and server name. */
1002
0
      workaround = pxe_uefi_workaround(pxearch, tagif_netid, mess, tmp->local, now, pxe);
1003
      
1004
0
      if (!workaround && boot)
1005
0
        {
1006
          /* Provide the bootfile here, for iPXE, and in case we have no menu items
1007
       and set discovery_control = 8 */
1008
0
          if (boot->next_server.s_addr) 
1009
0
      mess->siaddr = boot->next_server;
1010
0
          else if (boot->tftp_sname) 
1011
0
      mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
1012
          
1013
0
          if (boot->file)
1014
0
      safe_strncpy((char *)mess->file, boot->file, sizeof(mess->file));
1015
0
        }
1016
      
1017
0
      option_put(mess, end, OPTION_MESSAGE_TYPE, 1, 
1018
0
           mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
1019
0
      option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
1020
0
      pxe_misc(mess, end, uuid, pxevendor);
1021
0
      prune_vendor_opts(tagif_netid);
1022
0
      if ((pxe && !workaround) || !redirect4011)
1023
0
        do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
1024
1025
      /* dhcp-option-pxe ONLY */
1026
0
      for (option = daemon->dhcp_opts; option; option = option->next)
1027
0
        {
1028
0
          int len;
1029
0
          unsigned char *p;
1030
          
1031
0
          if (!(option->flags & DHOPT_TAGOK))
1032
0
      continue;
1033
          
1034
0
          len = do_opt(option, NULL, tmp, borken_opt);
1035
1036
0
          if ((p = free_space(mess, end, option->opt, len)))
1037
0
      do_opt(option, p, tmp, borken_opt);
1038
0
        }
1039
1040
0
      handle_encap(mess, end, req_options, borken_opt, tagif_netid, 2);
1041
      
1042
0
      daemon->metrics[METRIC_PXE]++;
1043
0
      log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
1044
0
      log_tags(tagif_netid, ntohl(mess->xid));
1045
0
      if (!ignore)
1046
0
        apply_delay(mess->xid, recvtime, tagif_netid);
1047
0
      return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);   
1048
0
    }
1049
0
      }
1050
0
  }
1051
0
    }
1052
1053
  /* if we're just a proxy server, go no further */
1054
0
  if (mess_type != DHCPLEASEQUERY &&
1055
0
      ((context->flags & CONTEXT_PROXY) || pxe))
1056
0
    return 0;
1057
  
1058
0
  if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
1059
0
    {
1060
0
      req_options = (unsigned char *)daemon->dhcp_buff2;
1061
0
      memcpy(req_options, option_ptr(opt, 0), option_len(opt));
1062
0
      req_options[option_len(opt)] = OPTION_END;
1063
0
    }
1064
  
1065
0
  switch (mess_type)
1066
0
    {
1067
0
    case DHCPLEASEQUERY:
1068
0
      mess_type = DHCPLEASEUNKNOWN;
1069
      
1070
0
      if (!option_bool(OPT_LEASEQUERY))
1071
0
  return 0;
1072
      
1073
0
      if (leasequery_source.s_addr == 0)
1074
0
  return 0;
1075
1076
0
      inet_ntop(AF_INET, &leasequery_source, daemon->workspacename, ADDRSTRLEN);
1077
1078
0
      if (daemon->leasequery_addr)
1079
0
  {
1080
0
    struct bogus_addr *baddrp;
1081
1082
0
    for (baddrp = daemon->leasequery_addr; baddrp; baddrp = baddrp->next)
1083
0
      if (!baddrp->is6 && is_same_net_prefix(leasequery_source, baddrp->addr.addr4, baddrp->prefix))
1084
0
        break;
1085
    
1086
0
    if (!baddrp)
1087
0
      {
1088
0
        my_syslog(MS_DHCP | LOG_WARNING, _("leasequery from %s not permitted"), daemon->workspacename);
1089
0
        return 0;
1090
0
      }
1091
0
  }
1092
      
1093
0
      daemon->metrics[METRIC_DHCPLEASEQUERY]++;
1094
0
      log_packet("DHCPLEASEQUERY", mess->ciaddr.s_addr ? &mess->ciaddr : NULL, emac_len != 0 ? emac : NULL, emac_len,
1095
0
     iface_name, "from ", daemon->workspacename, mess->xid);
1096
1097
      /* Put all the contexts on the ->current list for the next stages. */
1098
0
      for (context = daemon->dhcp; context; context = context->next)
1099
0
  context->current = context->next;
1100
      
1101
      /* Have maybe already found the lease by MAC or clid. */
1102
0
      if (mess->ciaddr.s_addr != 0 &&
1103
0
    !(lease = lease_find_by_addr(mess->ciaddr)) &&
1104
0
    address_available(daemon->dhcp, mess->ciaddr, tagif_netid))
1105
0
  {
1106
0
    mess_type = DHCPLEASEUNASSIGNED;
1107
0
    daemon->metrics[METRIC_DHCPLEASEUNASSIGNED]++;
1108
0
  }
1109
      
1110
0
      if (lease)
1111
0
  {
1112
    /* RFC4388 para 6.4.2 */
1113
0
    if (lease->agent_id)
1114
0
      {
1115
0
        unsigned char *sopt ;
1116
        
1117
0
        for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
1118
0
    {
1119
0
      int search;
1120
      
1121
0
      if (vendor->match_type == MATCH_CIRCUIT)
1122
0
        search = SUBOPT_CIRCUIT_ID;
1123
0
      else if (vendor->match_type == MATCH_REMOTE)
1124
0
        search = SUBOPT_REMOTE_ID;
1125
0
      else if (vendor->match_type == MATCH_SUBSCRIBER)
1126
0
        search = SUBOPT_SUBSCR_ID;
1127
0
      else 
1128
0
        continue;
1129
      
1130
0
      if ((sopt = option_find1(lease->agent_id, lease->agent_id + lease->agent_id_len, search, 1)) &&
1131
0
          vendor->len == option_len(sopt) &&
1132
0
          memcmp(option_ptr(sopt, 0), vendor->data, vendor->len) == 0)
1133
0
        {
1134
0
          vendor->netid.next = netid;
1135
0
          netid = &vendor->netid;
1136
0
        }
1137
0
    }
1138
        
1139
0
        tagif_netid = run_tag_if(netid);
1140
0
      }
1141
    
1142
    /* Now find the context for this lease and config for this host. */
1143
0
    if ((context = narrow_context(daemon->dhcp, lease->addr, tagif_netid)))
1144
0
      {
1145
0
        if ((config = find_config(daemon->dhcp_conf, context, lease->clid, lease->clid_len, 
1146
0
          lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, lease->hostname, tagif_netid)))
1147
0
    {
1148
0
      struct dhcp_netid_list *list;
1149
      
1150
0
      for (list = config->netid; list; list = list->next)
1151
0
        {
1152
0
          list->list->next = netid;
1153
0
          netid = list->list;
1154
0
        }
1155
1156
0
      tagif_netid = run_tag_if(netid);
1157
0
    }
1158
        
1159
0
        if (context->netid.net)
1160
0
    {
1161
0
      context->netid.next = netid;
1162
0
      tagif_netid = run_tag_if(&context->netid);
1163
0
    }
1164
1165
0
        log_tags(tagif_netid, ntohl(mess->xid));
1166
0
        emac = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len, lease->hwaddr, lease->clid_len, lease->clid, &emac_len);
1167
0
        mess_type = DHCPLEASEACTIVE;
1168
0
        daemon->metrics[METRIC_DHCPLEASEACTIVE]++;
1169
0
      }
1170
0
  }
1171
      
1172
0
      log_packet(mess_type == DHCPLEASEACTIVE ? "DHCPLEASEACTIVE" : (mess_type == DHCPLEASEUNASSIGNED ? "DHCPLEASEUNASSIGNED" : "DHCPLEASEUNKNOWN"),
1173
0
     mess_type == DHCPLEASEACTIVE ? &lease->addr : (mess->ciaddr.s_addr != 0 ? &mess->ciaddr : NULL),
1174
0
     emac_len != 0 ? emac : NULL, emac_len,
1175
0
     iface_name, mess_type == DHCPLEASEACTIVE ? lease->hostname : NULL, NULL, mess->xid);
1176
      
1177
0
      clear_packet(mess, end);
1178
0
      option_put(mess, end, OPTION_MESSAGE_TYPE, 1, mess_type);
1179
      
1180
0
      if (mess_type == DHCPLEASEUNKNOWN)
1181
0
  {
1182
0
    daemon->metrics[METRIC_DHCPLEASEUNKNOWN]++;
1183
0
    mess->ciaddr.s_addr = 0;
1184
0
  }
1185
      
1186
0
      if (mess_type == DHCPLEASEACTIVE)
1187
0
  {
1188
0
    unsigned char *p;
1189
    
1190
0
    mess->ciaddr = lease->addr;
1191
0
    mess->hlen = lease->hwaddr_len;
1192
0
    mess->htype = lease->hwaddr_type;
1193
0
    memcpy(mess->chaddr, lease->hwaddr, lease->hwaddr_len);
1194
    
1195
0
    if (lease->clid && in_list(req_options, OPTION_CLIENT_ID) &&
1196
0
        (p = free_space(mess, end, OPTION_CLIENT_ID, lease->clid_len)))
1197
0
      memcpy(p, lease->clid, lease->clid_len);
1198
    
1199
0
    if (in_list(req_options, OPTION_LEASE_TIME))
1200
0
      {
1201
0
        if (lease->expires == 0) /* infinite lease */
1202
0
    option_put(mess, end, OPTION_LEASE_TIME, 4, 0xffffffff);
1203
0
        else
1204
0
    option_put(mess, end, OPTION_LEASE_TIME, 4, (unsigned int)(lease->expires - now));
1205
0
      }
1206
    
1207
0
    if (lease->expires != 0)
1208
0
      {
1209
0
        time = calc_time(context, config, NULL);
1210
1211
0
        if (in_list(req_options, OPTION_T1) && (lease->expires - now) > time/2)
1212
0
    option_put(mess, end, OPTION_T1, 4, ((unsigned int)(lease->expires - now)) - time/2);
1213
0
        if (in_list(req_options, OPTION_T2) && (lease->expires - now) > time/8)
1214
0
    option_put(mess, end, OPTION_T2, 4, ((unsigned int)(lease->expires - now)) - time/8);
1215
0
        if (in_list(req_options, OPTION_LAST_TRANSACTION) && (lease->expires - now) < time)
1216
0
    option_put(mess, end, OPTION_LAST_TRANSACTION, 4, time - ((unsigned int)(lease->expires - now)));
1217
0
      }
1218
    
1219
0
    if (lease->vendorclass)
1220
0
      {
1221
0
        memcpy(daemon->dhcp_buff3, lease->vendorclass, lease->vendorclass_len);
1222
0
        vendor_class_len = lease->vendorclass_len;
1223
0
      }
1224
    
1225
0
    subnet_addr.s_addr = 0;
1226
0
    do_options(context, mess, end, req_options, lease->hostname, get_domain(lease->addr), netid, subnet_addr,
1227
0
         0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0, NULL, 1);
1228
    
1229
    /* Does this have to be last for leasequery replies also? RFC 4388 is silent on the subject. */
1230
0
    if (lease->agent_id && in_list(req_options, OPTION_AGENT_ID) &&
1231
0
        (p = free_space(mess, end, OPTION_AGENT_ID, lease->agent_id_len)))
1232
0
      memcpy(p, lease->agent_id, lease->agent_id_len);
1233
0
  }
1234
      
1235
0
      return dhcp_packet_size(mess, NULL, real_end);
1236
            
1237
0
    case DHCPDECLINE:
1238
0
      if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
1239
0
    option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
1240
0
  return 0;
1241
      
1242
      /* sanitise any message. Paranoid? Moi? */
1243
0
      sanitise(option_find(mess, sz, OPTION_MESSAGE, 1), daemon->dhcp_buff);
1244
      
1245
0
      if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
1246
0
  return 0;
1247
      
1248
0
      daemon->metrics[METRIC_DHCPDECLINE]++;
1249
0
      log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid);
1250
      
1251
0
      if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
1252
0
  lease_prune(lease, now);
1253
      
1254
0
      if (have_config(config, CONFIG_ADDR) && 
1255
0
    config->addr.s_addr == option_addr(opt).s_addr)
1256
0
  {
1257
0
    prettyprint_time(daemon->dhcp_buff, DECLINE_BACKOFF);
1258
0
    inet_ntop(AF_INET, &config->addr, daemon->addrbuff, ADDRSTRLEN);
1259
0
    my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"), 
1260
0
        daemon->addrbuff, daemon->dhcp_buff);
1261
0
    config->flags |= CONFIG_DECLINED;
1262
0
    config->decline_time = now;
1263
0
  }
1264
0
      else
1265
  /* make sure this host gets a different address next time. */
1266
0
  for (; context; context = context->current)
1267
0
    context->addr_epoch++;
1268
      
1269
0
      return 0;
1270
1271
0
    case DHCPRELEASE:
1272
0
      if (!(context = narrow_context(context, mess->ciaddr, tagif_netid)) ||
1273
0
    !(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
1274
0
    option_addr(opt).s_addr != server_id(context, override, fallback).s_addr)
1275
0
  return 0;
1276
      
1277
0
      if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
1278
0
  lease_prune(lease, now);
1279
0
      else
1280
0
  message = _("unknown lease");
1281
1282
0
      daemon->metrics[METRIC_DHCPRELEASE]++;
1283
0
      log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
1284
  
1285
0
      return 0;
1286
      
1287
0
    case DHCPDISCOVER:
1288
0
      if (ignore || have_config(config, CONFIG_DISABLE))
1289
0
  {
1290
0
    if (option_bool(OPT_QUIET_DHCP))
1291
0
      return 0;
1292
0
    message = _("ignored");
1293
0
    opt = NULL;
1294
0
  }
1295
0
      else 
1296
0
  {
1297
0
    struct in_addr addr, conf;
1298
    
1299
0
    addr.s_addr = conf.s_addr = 0;
1300
1301
0
    if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))  
1302
0
      addr = option_addr(opt);
1303
    
1304
0
    if (have_config(config, CONFIG_ADDR))
1305
0
      {
1306
0
        inet_ntop(AF_INET, &config->addr, daemon->addrbuff, ADDRSTRLEN);
1307
        
1308
0
        if ((ltmp = lease_find_by_addr(config->addr)) && 
1309
0
      ltmp != lease &&
1310
0
      !config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
1311
0
    {
1312
0
      int len;
1313
0
      unsigned char *mac = extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len,
1314
0
                   ltmp->hwaddr, ltmp->clid_len, ltmp->clid, &len);
1315
0
      my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s"),
1316
0
          daemon->addrbuff, print_mac(mac, len));
1317
0
    }
1318
0
        else
1319
0
    {
1320
0
      struct dhcp_context *tmp;
1321
0
      for (tmp = context; tmp; tmp = tmp->current)
1322
0
        if (context->router.s_addr == config->addr.s_addr)
1323
0
          break;
1324
0
      if (tmp)
1325
0
        my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by the server or relay"), daemon->addrbuff);
1326
0
      else if (have_config(config, CONFIG_DECLINED) &&
1327
0
         difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
1328
0
        my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), daemon->addrbuff);
1329
0
      else
1330
0
        conf = config->addr;
1331
0
    }
1332
0
      }
1333
    
1334
0
    if (conf.s_addr)
1335
0
      mess->yiaddr = conf;
1336
0
    else if (lease && 
1337
0
       address_available(context, lease->addr, tagif_netid) && 
1338
0
       !config_find_by_address(daemon->dhcp_conf, lease->addr))
1339
0
      mess->yiaddr = lease->addr;
1340
0
    else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) && 
1341
0
       !config_find_by_address(daemon->dhcp_conf, addr) && do_icmp_ping(now, addr, 0, loopback))
1342
0
      mess->yiaddr = addr;
1343
0
    else if (emac_len == 0)
1344
0
      message = _("no unique-id");
1345
0
    else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, tagif_netid, now, loopback))
1346
0
      message = _("no address available");      
1347
0
  }
1348
      
1349
0
      daemon->metrics[METRIC_DHCPDISCOVER]++;
1350
0
      log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid); 
1351
1352
0
      if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
1353
0
  return 0;
1354
1355
0
      if (context->netid.net)
1356
0
  {
1357
0
    context->netid.next = netid;
1358
0
    tagif_netid = run_tag_if(&context->netid);
1359
0
  }
1360
1361
0
      apply_delay(mess->xid, recvtime, tagif_netid);
1362
1363
0
      if (option_bool(OPT_RAPID_COMMIT) && option_find(mess, sz, OPTION_RAPID_COMMIT, 0))
1364
0
  {
1365
0
    rapid_commit = 1;
1366
    /* If a lease exists for this host and another address, squash it. */
1367
0
    if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
1368
0
      {
1369
0
        lease_prune(lease, now);
1370
0
        lease = NULL;
1371
0
      }
1372
0
    goto rapid_commit;
1373
0
  }
1374
      
1375
0
      log_tags(tagif_netid, ntohl(mess->xid));
1376
1377
0
      daemon->metrics[METRIC_DHCPOFFER]++;
1378
0
      log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
1379
      
1380
0
      time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
1381
0
      clear_packet(mess, end);
1382
0
      option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
1383
0
      option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1384
0
      option_put(mess, end, OPTION_LEASE_TIME, 4, time);
1385
      /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
1386
0
      do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr), 
1387
0
     netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor, 0);
1388
      
1389
0
      return dhcp_packet_size(mess, agent_id, real_end);
1390
  
1391
1392
0
    case DHCPREQUEST:
1393
0
      if (ignore || have_config(config, CONFIG_DISABLE))
1394
0
  return 0;
1395
0
      if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
1396
0
  {
1397
    /* SELECTING  or INIT_REBOOT */
1398
0
    mess->yiaddr = option_addr(opt);
1399
    
1400
    /* send vendor and user class info for new or recreated lease */
1401
0
    do_classes = 1;
1402
    
1403
0
    if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)))
1404
0
      {
1405
        /* SELECTING */
1406
0
        selecting = 1;
1407
        
1408
0
        if (override.s_addr != 0)
1409
0
    {
1410
0
      if (option_addr(opt).s_addr != override.s_addr)
1411
0
        return 0;
1412
0
    }
1413
0
        else 
1414
0
    {
1415
0
      for (; context; context = context->current)
1416
0
        if (context->local.s_addr == option_addr(opt).s_addr)
1417
0
          break;
1418
      
1419
0
      if (!context)
1420
0
        {
1421
          /* Handle very strange configs where clients have more than one route to the server.
1422
       If a clients idea of its server-id matches any of our DHCP interfaces, we let it pass.
1423
       Have to set override to make sure we echo back the correct server-id */
1424
0
          struct irec *intr;
1425
          
1426
0
          enumerate_interfaces(0);
1427
1428
0
          for (intr = daemon->interfaces; intr; intr = intr->next)
1429
0
      if (intr->addr.sa.sa_family == AF_INET &&
1430
0
          intr->addr.in.sin_addr.s_addr == option_addr(opt).s_addr &&
1431
0
          intr->tftp_ok)
1432
0
        break;
1433
1434
0
          if (intr)
1435
0
      override = intr->addr.in.sin_addr;
1436
0
          else
1437
0
      {
1438
        /* In auth mode, a REQUEST sent to the wrong server
1439
           should be faulted, so that the client establishes 
1440
           communication with us, otherwise, silently ignore. */
1441
0
        if (!option_bool(OPT_AUTHORITATIVE))
1442
0
          return 0;
1443
0
        message = _("wrong server-ID");
1444
0
      }
1445
0
        }
1446
0
    }
1447
1448
        /* If a lease exists for this host and another address, squash it. */
1449
0
        if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
1450
0
    {
1451
0
      lease_prune(lease, now);
1452
0
      lease = NULL;
1453
0
    }
1454
0
      }
1455
0
    else
1456
0
      {
1457
        /* INIT-REBOOT */
1458
0
        if (!lease && !option_bool(OPT_AUTHORITATIVE))
1459
0
    return 0;
1460
        
1461
0
        if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
1462
0
    message = _("wrong address");
1463
0
      }
1464
0
  }
1465
0
      else
1466
0
  {
1467
    /* RENEWING or REBINDING */ 
1468
    /* Check existing lease for this address.
1469
       We allow it to be missing if dhcp-authoritative mode
1470
       as long as we can allocate the lease now - checked below.
1471
       This makes for a smooth recovery from a lost lease DB */
1472
0
    if ((lease && mess->ciaddr.s_addr != lease->addr.s_addr) ||
1473
0
        (!lease && !option_bool(OPT_AUTHORITATIVE)))
1474
0
      {
1475
        /* A client rebinding will broadcast the request, so we may see it even 
1476
     if the lease is held by another server. Just ignore it in that case. 
1477
     If the request is unicast to us, then somethings wrong, NAK */
1478
0
        if (!unicast_dest)
1479
0
    return 0;
1480
0
        message = _("lease not found");
1481
        /* ensure we broadcast NAK */
1482
0
        unicast_dest = 0;
1483
0
      }
1484
1485
    /* desynchronise renewals */
1486
0
    fuzz = rand16();
1487
0
    mess->yiaddr = mess->ciaddr;
1488
0
  }
1489
1490
0
      daemon->metrics[METRIC_DHCPREQUEST]++;
1491
0
      log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
1492
      
1493
0
    rapid_commit:
1494
0
      if (!message)
1495
0
  {
1496
0
    struct dhcp_config *addr_config;
1497
0
    struct dhcp_context *tmp = NULL;
1498
    
1499
0
    if (have_config(config, CONFIG_ADDR))
1500
0
      for (tmp = context; tmp; tmp = tmp->current)
1501
0
        if (context->router.s_addr == config->addr.s_addr)
1502
0
    break;
1503
    
1504
0
    if (!(context = narrow_context(context, mess->yiaddr, tagif_netid)))
1505
0
      {
1506
        /* If a machine moves networks whilst it has a lease, we catch that here. */
1507
0
        message = _("wrong network");
1508
        /* ensure we broadcast NAK */
1509
0
        unicast_dest = 0;
1510
0
      }
1511
    
1512
    /* Check for renewal of a lease which is outside the allowed range. */
1513
0
    else if (!address_available(context, mess->yiaddr, tagif_netid) &&
1514
0
       (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
1515
0
      message = _("address not available");
1516
    
1517
    /* Check if a new static address has been configured. Be very sure that
1518
       when the client does DISCOVER, it will get the static address, otherwise
1519
       an endless protocol loop will ensue. */
1520
0
    else if (!tmp && !selecting &&
1521
0
       have_config(config, CONFIG_ADDR) && 
1522
0
       (!have_config(config, CONFIG_DECLINED) ||
1523
0
        difftime(now, config->decline_time) > (float)DECLINE_BACKOFF) &&
1524
0
       config->addr.s_addr != mess->yiaddr.s_addr &&
1525
0
       (!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
1526
0
      message = _("static lease available");
1527
1528
    /* Check to see if the address is reserved as a static address for another host */
1529
0
    else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && addr_config != config)
1530
0
      message = _("address reserved");
1531
1532
0
    else if (!lease && (ltmp = lease_find_by_addr(mess->yiaddr)))
1533
0
      {
1534
        /* If a host is configured with more than one MAC address, it's OK to 'nix 
1535
     a lease from one of its MACs to give the address to another. */
1536
0
        if (config && config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
1537
0
    {
1538
0
      inet_ntop(AF_INET, &ltmp->addr, daemon->addrbuff, ADDRSTRLEN);
1539
0
      my_syslog(MS_DHCP | LOG_INFO, _("abandoning lease to %s of %s"),
1540
0
          print_mac(ltmp->hwaddr, ltmp->hwaddr_len), 
1541
0
          daemon->addrbuff);
1542
0
      lease = ltmp;
1543
0
    }
1544
0
        else
1545
0
    message = _("address in use");
1546
0
      }
1547
1548
0
    if (!message)
1549
0
      {
1550
0
        if (emac_len == 0)
1551
0
    message = _("no unique-id");
1552
        
1553
0
        else if (!lease)
1554
0
    {      
1555
0
      if ((lease = lease4_allocate(mess->yiaddr)))
1556
0
        do_classes = 1;
1557
0
      else
1558
0
        message = _("no leases left");
1559
0
    }
1560
0
      }
1561
0
  }
1562
1563
0
      if (message)
1564
0
  {
1565
0
    daemon->metrics[rapid_commit ? METRIC_NOANSWER : METRIC_DHCPNAK]++;
1566
0
    log_packet(rapid_commit ? "NOANSWER" : "DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
1567
1568
    /* rapid commit case: lease allocate failed but don't send DHCPNAK */
1569
0
    if (rapid_commit)
1570
0
      return 0;
1571
    
1572
0
    mess->yiaddr.s_addr = 0;
1573
0
    clear_packet(mess, end);
1574
0
    option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
1575
0
    option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1576
0
    option_put_string(mess, end, OPTION_MESSAGE, message, borken_opt);
1577
    /* This fixes a problem with the DHCP spec, broadcasting a NAK to a host on 
1578
       a distant subnet which unicast a REQ to us won't work. */
1579
0
    if (!unicast_dest || mess->giaddr.s_addr != 0 || 
1580
0
        mess->ciaddr.s_addr == 0 || is_same_net(context->local, mess->ciaddr, context->netmask))
1581
0
      {
1582
0
        mess->flags |= htons(0x8000); /* broadcast */
1583
0
        mess->ciaddr.s_addr = 0;
1584
0
      }
1585
0
  }
1586
0
      else
1587
0
  {
1588
0
    if (context->netid.net)
1589
0
      {
1590
0
        context->netid.next = netid;
1591
0
        tagif_netid = run_tag_if( &context->netid);
1592
0
      }
1593
1594
0
    log_tags(tagif_netid, ntohl(mess->xid));
1595
    
1596
0
    if (do_classes)
1597
0
      {
1598
        /* pick up INIT-REBOOT events. */
1599
0
        lease->flags |= LEASE_CHANGED;
1600
1601
0
#ifdef HAVE_SCRIPT
1602
0
        if (daemon->lease_change_command)
1603
0
    {
1604
0
      struct dhcp_netid *n;
1605
      
1606
0
      if (mess->giaddr.s_addr)
1607
0
        lease->giaddr = mess->giaddr;
1608
      
1609
0
      free(lease->extradata);
1610
0
      lease->extradata = NULL;
1611
0
      lease->extradata_size = lease->extradata_len = 0;
1612
      
1613
0
      add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
1614
0
      lease_add_extradata(lease, (unsigned char *)client_hostname, 
1615
0
            client_hostname ? strlen(client_hostname) : 0, 0);
1616
0
      add_extradata_opt(lease, oui);
1617
0
      add_extradata_opt(lease, serial);
1618
0
      add_extradata_opt(lease, class);
1619
1620
0
      if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
1621
0
        {
1622
0
          add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_CIRCUIT_ID, 1));
1623
0
          add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBSCR_ID, 1));
1624
0
          add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_REMOTE_ID, 1));
1625
0
        }
1626
0
      else
1627
0
        {
1628
0
          add_extradata_opt(lease, NULL);
1629
0
          add_extradata_opt(lease, NULL);
1630
0
          add_extradata_opt(lease, NULL);
1631
0
        }
1632
1633
      /* DNSMASQ_REQUESTED_OPTIONS */
1634
0
      if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 1)))
1635
0
        {
1636
0
          int i, len = option_len(opt);
1637
0
          unsigned char *rop = option_ptr(opt, 0);
1638
          
1639
0
          for (i = 0; i < len; i++)
1640
0
      lease_add_extradata(lease, (unsigned char *)daemon->namebuff,
1641
0
              sprintf(daemon->namebuff, "%u", rop[i]), (i + 1) == len ? 0 : ',');
1642
0
        }
1643
0
      else
1644
0
        lease_add_extradata(lease, NULL, 0, 0);
1645
      
1646
0
      add_extradata_opt(lease, option_find(mess, sz, OPTION_MUD_URL_V4, 1));
1647
      
1648
      /* space-concat tag set */
1649
0
      if (!tagif_netid)
1650
0
        add_extradata_opt(lease, NULL);
1651
0
      else
1652
0
        for (n = tagif_netid; n; n = n->next)
1653
0
          {
1654
0
      struct dhcp_netid *n1;
1655
      /* kill dupes */
1656
0
      for (n1 = n->next; n1; n1 = n1->next)
1657
0
        if (strcmp(n->net, n1->net) == 0)
1658
0
          break;
1659
0
      if (!n1)
1660
0
        lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0); 
1661
0
          }
1662
      
1663
0
      if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
1664
0
        {
1665
0
          int len = option_len(opt);
1666
0
          unsigned char *ucp = option_ptr(opt, 0);
1667
          /* If the user-class option started as counted strings, the first byte will be zero. */
1668
0
          if (len != 0 && ucp[0] == 0)
1669
0
      ucp++, len--;
1670
0
          lease_add_extradata(lease, ucp, len, -1);
1671
0
        }
1672
0
    }
1673
0
#endif
1674
0
      }
1675
    
1676
0
    if (!hostname_auth && (client_hostname = host_from_dns(mess->yiaddr)))
1677
0
      {
1678
0
        domain = get_domain(mess->yiaddr);
1679
0
        hostname = client_hostname;
1680
0
        hostname_auth = 1;
1681
0
      }
1682
    
1683
0
    time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
1684
0
    lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len, now, do_classes);
1685
    
1686
    /* if all the netids in the ignore_name list are present, ignore client-supplied name */
1687
0
    if (!hostname_auth)
1688
0
      {
1689
0
        for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1690
0
    if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
1691
0
      break;
1692
0
        if (id_list)
1693
0
    hostname = NULL;
1694
0
      }
1695
    
1696
    /* Last ditch, if configured, generate hostname from mac address */
1697
0
    if (!hostname && emac_len != 0)
1698
0
      {
1699
0
        for (id_list = daemon->dhcp_gen_names; id_list; id_list = id_list->next)
1700
0
    if ((!id_list->list) || match_netid(id_list->list, tagif_netid, 0))
1701
0
      break;
1702
0
        if (id_list)
1703
0
    {
1704
0
      int i;
1705
1706
0
      hostname = daemon->dhcp_buff;
1707
      /* buffer is 256 bytes, 3 bytes per octet */
1708
0
      for (i = 0; (i < emac_len) && (i < 80); i++)
1709
0
        hostname += sprintf(hostname, "%.2x%s", emac[i], (i == emac_len - 1) ? "" : "-");
1710
0
      hostname = daemon->dhcp_buff;
1711
0
    }
1712
0
      }
1713
1714
0
    if (hostname)
1715
0
      lease_set_hostname(lease, hostname, hostname_auth, get_domain(lease->addr), domain);
1716
    
1717
0
    lease_set_expires(lease, time, now);
1718
0
    lease_set_interface(lease, int_index, now);
1719
    
1720
0
    if (option_bool(OPT_LEASEQUERY))
1721
0
      {
1722
0
        if (agent_id)
1723
0
    lease_set_agent_id(lease, option_ptr(agent_id, 0), option_len(agent_id));
1724
0
        if (vendor_class_len != 0)
1725
0
    lease_set_vendorclass(lease, (unsigned char *)daemon->dhcp_buff3, vendor_class_len);
1726
0
      }
1727
0
    else
1728
0
      {
1729
        /* if leasequery no longer enabled, remove stuff that may have been stored when it was. */
1730
0
        lease_set_agent_id(lease, NULL, 0);
1731
0
        lease_set_vendorclass(lease, NULL, 0);
1732
0
      }
1733
    
1734
0
    if (override.s_addr != 0)
1735
0
      lease->override = override;
1736
0
    else
1737
0
      override = lease->override;
1738
1739
0
    daemon->metrics[METRIC_DHCPACK]++;
1740
0
    log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);  
1741
1742
0
    clear_packet(mess, end);
1743
0
    option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
1744
0
    option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1745
0
    option_put(mess, end, OPTION_LEASE_TIME, 4, time);
1746
0
    if (rapid_commit)
1747
0
       option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0);
1748
0
     do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr), 
1749
0
          netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor, 0);
1750
0
  }
1751
1752
0
      return dhcp_packet_size(mess, agent_id, real_end); 
1753
      
1754
0
    case DHCPINFORM:
1755
0
      if (ignore || have_config(config, CONFIG_DISABLE))
1756
0
  message = _("ignored");
1757
      
1758
0
      daemon->metrics[METRIC_DHCPINFORM]++;
1759
0
      log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid);
1760
     
1761
0
      if (message || mess->ciaddr.s_addr == 0)
1762
0
  return 0;
1763
1764
      /* For DHCPINFORM only, cope without a valid context */
1765
0
      context = narrow_context(context, mess->ciaddr, tagif_netid);
1766
      
1767
      /* Find a least based on IP address if we didn't
1768
   get one from MAC address/client-d */
1769
0
      if (!lease &&
1770
0
    (lease = lease_find_by_addr(mess->ciaddr)) && 
1771
0
    lease->hostname)
1772
0
  hostname = lease->hostname;
1773
      
1774
0
      if (!hostname)
1775
0
  hostname = host_from_dns(mess->ciaddr);
1776
      
1777
0
      if (context && context->netid.net)
1778
0
  {
1779
0
    context->netid.next = netid;
1780
0
    tagif_netid = run_tag_if(&context->netid);
1781
0
  }
1782
1783
0
      log_tags(tagif_netid, ntohl(mess->xid));
1784
      
1785
0
      daemon->metrics[METRIC_DHCPACK]++;
1786
0
      log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
1787
      
1788
0
      if (lease)
1789
0
  {
1790
0
    lease_set_interface(lease, int_index, now);
1791
0
    if (override.s_addr != 0)
1792
0
      lease->override = override;
1793
0
    else
1794
0
      override = lease->override;
1795
0
  }
1796
1797
0
      clear_packet(mess, end);
1798
0
      option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
1799
0
      option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
1800
     
1801
      /* RFC 2131 says that DHCPINFORM shouldn't include lease-time parameters, but 
1802
   we supply a utility which makes DHCPINFORM requests to get this information.
1803
   Only include lease time if OPTION_LEASE_TIME is in the parameter request list,
1804
   which won't be true for ordinary clients, but will be true for the 
1805
   dhcp_lease_time utility. */
1806
0
      if (lease && in_list(req_options, OPTION_LEASE_TIME))
1807
0
  {
1808
0
    if (lease->expires == 0)
1809
0
      time = 0xffffffff;
1810
0
    else
1811
0
      time = (unsigned int)difftime(lease->expires, now);
1812
0
    option_put(mess, end, OPTION_LEASE_TIME, 4, time);
1813
0
  }
1814
1815
0
      do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
1816
0
     netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0, pxevendor, 0);
1817
      
1818
0
      *is_inform = 1; /* handle reply differently */
1819
0
      return dhcp_packet_size(mess, agent_id, real_end); 
1820
0
    }
1821
  
1822
0
  return 0;
1823
0
}
1824
1825
/* find a good value to use as MAC address for logging and address-allocation hashing.
1826
   This is normally just the chaddr field from the DHCP packet,
1827
   but eg Firewire will have hlen == 0 and use the client-id instead. 
1828
   This could be anything, but will normally be EUI64 for Firewire.
1829
   We assume that if the first byte of the client-id equals the htype byte
1830
   then the client-id is using the usual encoding and use the rest of the 
1831
   client-id: if not we can use the whole client-id. This should give
1832
   sane MAC address logs. */
1833
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr, 
1834
              int clid_len, unsigned char *clid, int *len_out)
1835
0
{
1836
0
  if (hwlen == 0 && clid && clid_len > 3)
1837
0
    {
1838
0
      if (clid[0]  == hwtype)
1839
0
  {
1840
0
    *len_out = clid_len - 1 ;
1841
0
    return clid + 1;
1842
0
  }
1843
1844
0
#if defined(ARPHRD_EUI64) && defined(ARPHRD_IEEE1394)
1845
0
      if (clid[0] ==  ARPHRD_EUI64 && hwtype == ARPHRD_IEEE1394)
1846
0
  {
1847
0
    *len_out = clid_len - 1 ;
1848
0
    return clid + 1;
1849
0
  }
1850
0
#endif
1851
      
1852
0
      *len_out = clid_len;
1853
0
      return clid;
1854
0
    }
1855
  
1856
0
  *len_out = hwlen;
1857
0
  return hwaddr;
1858
0
}
1859
1860
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt)
1861
0
{
1862
0
  unsigned int time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
1863
  
1864
0
  if (opt)
1865
0
    { 
1866
0
      unsigned int req_time = option_uint(opt, 0, 4);
1867
0
      if (req_time < 120 )
1868
0
  req_time = 120; /* sanity */
1869
0
      if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
1870
0
  time = req_time;
1871
0
    }
1872
1873
0
  return time;
1874
0
}
1875
1876
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback)
1877
0
{
1878
0
  if (override.s_addr != 0)
1879
0
    return override;
1880
0
  else if (context && context->local.s_addr != 0)
1881
0
    return context->local;
1882
0
  else
1883
0
    return fallback;
1884
0
}
1885
1886
static int sanitise(unsigned char *opt, char *buf)
1887
0
{
1888
0
  char *p;
1889
0
  int i;
1890
  
1891
0
  *buf = 0;
1892
  
1893
0
  if (!opt)
1894
0
    return 0;
1895
1896
0
  p = option_ptr(opt, 0);
1897
1898
0
  for (i = option_len(opt); i > 0; i--)
1899
0
    {
1900
0
      char c = *p++;
1901
0
      if (isprint((unsigned char)c))
1902
0
  *buf++ = c;
1903
0
    }
1904
0
  *buf = 0; /* add terminator */
1905
  
1906
0
  return 1;
1907
0
}
1908
1909
#ifdef HAVE_SCRIPT
1910
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
1911
0
{
1912
0
  if (!opt)
1913
0
    lease_add_extradata(lease, NULL, 0, 0);
1914
0
  else
1915
0
    lease_add_extradata(lease, option_ptr(opt, 0), option_len(opt), 0); 
1916
0
}
1917
#endif
1918
1919
static void log_packet(char *type, void *addr, unsigned char *ext_mac, 
1920
           int mac_len, char *interface, char *string, char *err, u32 xid)
1921
0
{
1922
0
  char *mac = "";
1923
1924
0
  if (!err && !option_bool(OPT_LOG_OPTS) && option_bool(OPT_QUIET_DHCP))
1925
0
    return;
1926
  
1927
0
  daemon->addrbuff[0] = 0;
1928
  
1929
0
  if (addr)
1930
0
    inet_ntop(AF_INET, addr, daemon->addrbuff, ADDRSTRLEN);
1931
  
1932
0
  if (ext_mac)
1933
0
    mac = print_mac(ext_mac, mac_len);
1934
  
1935
0
  if (option_bool(OPT_LOG_OPTS))
1936
0
    my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s%s%s%s",
1937
0
        ntohl(xid), 
1938
0
        type,
1939
0
        interface, 
1940
0
        daemon->addrbuff,
1941
0
        addr ? " " : "",
1942
0
        mac,
1943
0
        ext_mac ? " " : "",
1944
0
        string ? string : "",
1945
0
        err ? err : "");
1946
0
  else
1947
0
    my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s%s%s%s",
1948
0
        type,
1949
0
        interface, 
1950
0
        daemon->addrbuff,
1951
0
        addr ? " " : "",
1952
0
        mac,
1953
0
        ext_mac ? " " : "",
1954
0
        string ? string : "",
1955
0
        err ? err : "");
1956
  
1957
#ifdef HAVE_UBUS
1958
  if (!strcmp(type, "DHCPACK"))
1959
    ubus_event_bcast("dhcp.ack", mac, addr ? daemon->addrbuff : NULL, string, interface);
1960
  else if (!strcmp(type, "DHCPRELEASE"))
1961
    ubus_event_bcast("dhcp.release", mac, addr ? daemon->addrbuff : NULL, string, interface);
1962
#endif
1963
0
}
1964
1965
static void log_options(unsigned char *start, u32 xid)
1966
0
{
1967
0
  while (*start != OPTION_END)
1968
0
    {
1969
0
      char *optname = option_string(AF_INET, start[0], option_ptr(start, 0), option_len(start), daemon->namebuff, MAXDNAMESTR);
1970
      
1971
0
      my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d %s  %s", 
1972
0
    ntohl(xid), option_len(start), start[0], optname, daemon->namebuff);
1973
0
      start += start[1] + 2;
1974
0
    }
1975
0
}
1976
1977
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize)
1978
0
{
1979
0
  while (1) 
1980
0
    {
1981
0
      if (p >= end)
1982
0
  return NULL;
1983
0
      else if (*p == OPTION_END)
1984
0
  return opt == OPTION_END ? p : NULL;
1985
0
      else if (*p == OPTION_PAD)
1986
0
  p++;
1987
0
      else 
1988
0
  { 
1989
0
    int opt_len;
1990
0
    if (p > end - 2)
1991
0
      return NULL; /* malformed packet */
1992
0
    opt_len = option_len(p);
1993
0
    if (p > end - (2 + opt_len))
1994
0
      return NULL; /* malformed packet */
1995
0
    if (*p == opt && opt_len >= minsize)
1996
0
      return p;
1997
0
    p += opt_len + 2;
1998
0
  }
1999
0
    }
2000
0
}
2001
 
2002
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize)
2003
0
{
2004
0
  unsigned char *ret, *overload;
2005
  
2006
  /* skip over DHCP cookie; */
2007
0
  if ((ret = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, opt_type, minsize)))
2008
0
    return ret;
2009
2010
  /* look for overload option. */
2011
0
  if (!(overload = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, OPTION_OVERLOAD, 1)))
2012
0
    return NULL;
2013
  
2014
  /* Can we look in filename area ? */
2015
0
  if ((overload[2] & 1) &&
2016
0
      (ret = option_find1(&mess->file[0], &mess->file[128], opt_type, minsize)))
2017
0
    return ret;
2018
2019
  /* finally try sname area */
2020
0
  if ((overload[2] & 2) &&
2021
0
      (ret = option_find1(&mess->sname[0], &mess->sname[64], opt_type, minsize)))
2022
0
    return ret;
2023
2024
0
  return NULL;
2025
0
}
2026
2027
static struct in_addr option_addr(unsigned char *opt)
2028
0
{
2029
   /* this worries about unaligned data in the option. */
2030
  /* struct in_addr is network byte order */
2031
0
  struct in_addr ret;
2032
2033
0
  memcpy(&ret, option_ptr(opt, 0), INADDRSZ);
2034
2035
0
  return ret;
2036
0
}
2037
2038
static unsigned int option_uint(unsigned char *opt, int offset, int size)
2039
0
{
2040
  /* this worries about unaligned data and byte order */
2041
0
  unsigned int ret = 0;
2042
0
  int i;
2043
0
  unsigned char *p = option_ptr(opt, offset);
2044
  
2045
0
  for (i = 0; i < size; i++)
2046
0
    ret = (ret << 8) | *p++;
2047
2048
0
  return ret;
2049
0
}
2050
2051
static unsigned char *dhcp_skip_opts(unsigned char *start)
2052
0
{
2053
0
  while (*start != 0)
2054
0
    start += start[1] + 2;
2055
0
  return start;
2056
0
}
2057
2058
/* only for use when building packet: doesn't check for bad data. */ 
2059
static unsigned char *find_overload(struct dhcp_packet *mess)
2060
0
{
2061
0
  unsigned char *p = &mess->options[0] + sizeof(u32);
2062
  
2063
0
  while (*p != 0)
2064
0
    {
2065
0
      if (*p == OPTION_OVERLOAD)
2066
0
  return p;
2067
0
      p += p[1] + 2;
2068
0
    }
2069
0
  return NULL;
2070
0
}
2071
2072
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end)
2073
0
{
2074
0
  unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
2075
0
  unsigned char *overload;
2076
0
  size_t ret;
2077
  
2078
  /* move agent_id back down to the end of the packet */
2079
0
  if (agent_id)
2080
0
    {
2081
0
      memmove(p, agent_id, real_end - agent_id);
2082
0
      p += real_end - agent_id;
2083
0
      memset(p, 0, real_end - p); /* in case of overlap */
2084
0
    }
2085
  
2086
  /* add END options to the regions. */
2087
0
  overload = find_overload(mess);
2088
  
2089
0
  if (overload && (option_uint(overload, 0, 1) & 1))
2090
0
    {
2091
0
      *dhcp_skip_opts(mess->file) = OPTION_END;
2092
0
      if (option_bool(OPT_LOG_OPTS))
2093
0
  log_options(mess->file, mess->xid);
2094
0
    }
2095
0
  else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->file) != 0)
2096
0
    my_syslog(MS_DHCP | LOG_INFO, _("%u bootfile name: %s"), ntohl(mess->xid), (char *)mess->file);
2097
  
2098
0
  if (overload && (option_uint(overload, 0, 1) & 2))
2099
0
    {
2100
0
      *dhcp_skip_opts(mess->sname) = OPTION_END;
2101
0
      if (option_bool(OPT_LOG_OPTS))
2102
0
  log_options(mess->sname, mess->xid);
2103
0
    }
2104
0
  else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->sname) != 0)
2105
0
    my_syslog(MS_DHCP | LOG_INFO, _("%u server name: %s"), ntohl(mess->xid), (char *)mess->sname);
2106
2107
2108
0
  *p++ = OPTION_END;
2109
  
2110
0
  if (option_bool(OPT_LOG_OPTS))
2111
0
    {
2112
0
      if (mess->siaddr.s_addr != 0)
2113
0
  {
2114
0
    inet_ntop(AF_INET, &mess->siaddr, daemon->addrbuff, ADDRSTRLEN);
2115
0
    my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), daemon->addrbuff);
2116
0
  }
2117
      
2118
0
      if ((mess->flags & htons(0x8000)) && mess->ciaddr.s_addr == 0)
2119
0
  my_syslog(MS_DHCP | LOG_INFO, _("%u broadcast response"), ntohl(mess->xid));
2120
      
2121
0
      log_options(&mess->options[0] + sizeof(u32), mess->xid);
2122
0
    } 
2123
  
2124
0
  ret = (size_t)(p - (unsigned char *)mess);
2125
  
2126
0
  if (ret < MIN_PACKETSZ)
2127
0
    ret = MIN_PACKETSZ;
2128
  
2129
0
  return ret;
2130
0
}
2131
2132
static unsigned char *free_space(struct dhcp_packet *mess, unsigned char *end, int opt, int len)
2133
0
{
2134
0
  unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
2135
  
2136
0
  if (p + len + 3 >= end)
2137
    /* not enough space in options area, try and use overload, if poss */
2138
0
    {
2139
0
      unsigned char *overload;
2140
      
2141
0
      if (!(overload = find_overload(mess)) &&
2142
0
    (mess->file[0] == 0 || mess->sname[0] == 0))
2143
0
  {
2144
    /* attempt to overload fname and sname areas, we've reserved space for the
2145
       overflow option previuously. */
2146
0
    overload = p;
2147
0
    *(p++) = OPTION_OVERLOAD;
2148
0
    *(p++) = 1;
2149
0
  }
2150
      
2151
0
      p = NULL;
2152
      
2153
      /* using filename field ? */
2154
0
      if (overload)
2155
0
  {
2156
0
    if (mess->file[0] == 0)
2157
0
      overload[2] |= 1;
2158
    
2159
0
    if (overload[2] & 1)
2160
0
      {
2161
0
        p = dhcp_skip_opts(mess->file);
2162
0
        if (p + len + 3 >= mess->file + sizeof(mess->file))
2163
0
    p = NULL;
2164
0
      }
2165
    
2166
0
    if (!p)
2167
0
      {
2168
        /* try to bring sname into play (it may be already) */
2169
0
        if (mess->sname[0] == 0)
2170
0
    overload[2] |= 2;
2171
        
2172
0
        if (overload[2] & 2)
2173
0
    {
2174
0
      p = dhcp_skip_opts(mess->sname);
2175
0
      if (p + len + 3 >= mess->sname + sizeof(mess->sname))
2176
0
        p = NULL;
2177
0
    }
2178
0
      }
2179
0
  }
2180
      
2181
0
      if (!p)
2182
0
  my_syslog(MS_DHCP | LOG_WARNING, _("cannot send DHCP/BOOTP option %d: no space left in packet"), opt);
2183
0
    }
2184
 
2185
0
  if (p)
2186
0
    {
2187
0
      *(p++) = opt;
2188
0
      *(p++) = len;
2189
0
    }
2190
2191
0
  return p;
2192
0
}
2193
        
2194
static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val)
2195
0
{
2196
0
  int i;
2197
0
  unsigned char *p = free_space(mess, end, opt, len);
2198
  
2199
0
  if (p) 
2200
0
    for (i = 0; i < len; i++)
2201
0
      *(p++) = val >> (8 * (len - (i + 1)));
2202
0
}
2203
2204
static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt, 
2205
            const char *string, int null_term)
2206
0
{
2207
0
  unsigned char *p;
2208
0
  size_t len = strlen(string);
2209
2210
0
  if (null_term && len != 255)
2211
0
    len++;
2212
2213
0
  if ((p = free_space(mess, end, opt, len)))
2214
0
    memcpy(p, string, len);
2215
0
}
2216
2217
/* return length, note this only does the data part */
2218
static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *context, int null_term)
2219
0
{
2220
0
  int len = opt->len;
2221
  
2222
0
  if ((opt->flags & DHOPT_STRING) && null_term && len != 255)
2223
0
    len++;
2224
2225
0
  if (p && len != 0)
2226
0
    {
2227
0
      if (context && (opt->flags & DHOPT_ADDR))
2228
0
  {
2229
0
    int j;
2230
0
    struct in_addr *a = (struct in_addr *)opt->val;
2231
0
    for (j = 0; j < opt->len; j+=INADDRSZ, a++)
2232
0
      {
2233
        /* zero means "self" (but not in vendorclass options.) */
2234
0
        if (a->s_addr == 0)
2235
0
    memcpy(p, &context->local, INADDRSZ);
2236
0
        else
2237
0
    memcpy(p, a, INADDRSZ);
2238
0
        p += INADDRSZ;
2239
0
      }
2240
0
  }
2241
0
      else
2242
  /* empty string may be extended to "\0" by null_term */
2243
0
  memcpy(p, opt->val ? opt->val : (unsigned char *)"", len);
2244
0
    }  
2245
0
  return len;
2246
0
}
2247
2248
static int in_list(unsigned char *list, int opt)
2249
0
{
2250
0
  int i;
2251
2252
   /* If no requested options, send everything, not nothing. */
2253
0
  if (!list)
2254
0
    return 1;
2255
  
2256
0
  for (i = 0; list[i] != OPTION_END; i++)
2257
0
    if (opt == list[i])
2258
0
      return 1;
2259
2260
0
  return 0;
2261
0
}
2262
2263
static struct dhcp_opt *option_find2(int opt)
2264
0
{
2265
0
  struct dhcp_opt *opts;
2266
  
2267
0
  for (opts = daemon->dhcp_opts; opts; opts = opts->next)
2268
0
    if (opts->opt == opt && (opts->flags & DHOPT_TAGOK))
2269
0
      return opts;
2270
  
2271
0
  return NULL;
2272
0
}
2273
2274
/* mark vendor-encapsulated options which match the client-supplied  or
2275
   config-supplied vendor class */
2276
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
2277
0
{
2278
0
  for (; dopt; dopt = dopt->next)
2279
0
    {
2280
0
      dopt->flags &= ~DHOPT_VENDOR_MATCH;
2281
0
      if (opt && (dopt->flags & DHOPT_VENDOR))
2282
0
  {
2283
0
    const struct dhcp_pxe_vendor *pv;
2284
0
    struct dhcp_pxe_vendor dummy_vendor = {
2285
0
      .data = (char *)dopt->u.vendor_class,
2286
0
      .next = NULL,
2287
0
    };
2288
0
    if (dopt->flags & DHOPT_VENDOR_PXE)
2289
0
      pv = daemon->dhcp_pxe_vendors;
2290
0
    else
2291
0
      pv = &dummy_vendor;
2292
0
    for (; pv; pv = pv->next)
2293
0
      {
2294
0
        int i, len = 0, matched = 0;
2295
0
        if (pv->data)
2296
0
          len = strlen(pv->data);
2297
0
        for (i = 0; i <= (option_len(opt) - len); i++)
2298
0
          if (len == 0 || memcmp(pv->data, option_ptr(opt, i), len) == 0)
2299
0
            {
2300
0
        matched = 1;
2301
0
              break;
2302
0
            }
2303
0
        if (matched)
2304
0
    {
2305
0
            dopt->flags |= DHOPT_VENDOR_MATCH;
2306
0
      break;
2307
0
    }
2308
0
      }
2309
0
  }
2310
0
    }
2311
0
}
2312
2313
static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,  
2314
       struct dhcp_packet *mess, unsigned char *end, int null_term)
2315
0
{
2316
0
  int len, enc_len, ret = 0;
2317
0
  struct dhcp_opt *start;
2318
0
  unsigned char *p;
2319
    
2320
  /* find size in advance */
2321
0
  for (enc_len = 0, start = opt; opt; opt = opt->next)
2322
0
    if (opt->flags & flag)
2323
0
      {
2324
0
  int new = do_opt(opt, NULL, NULL, null_term) + 2;
2325
0
  ret  = 1;
2326
0
  if (enc_len + new <= 255)
2327
0
    enc_len += new;
2328
0
  else
2329
0
    {
2330
0
      p = free_space(mess, end, encap, enc_len);
2331
0
      for (; start && start != opt; start = start->next)
2332
0
        if (p && (start->flags & flag))
2333
0
    {
2334
0
      len = do_opt(start, p + 2, NULL, null_term);
2335
0
      *(p++) = start->opt;
2336
0
      *(p++) = len;
2337
0
      p += len;
2338
0
    }
2339
0
      enc_len = new;
2340
0
      start = opt;
2341
0
    }
2342
0
      }
2343
  
2344
0
  if (enc_len != 0 &&
2345
0
      (p = free_space(mess, end, encap, enc_len + 1)))
2346
0
    {
2347
0
      for (; start; start = start->next)
2348
0
  if (start->flags & flag)
2349
0
    {
2350
0
      len = do_opt(start, p + 2, NULL, null_term);
2351
0
      *(p++) = start->opt;
2352
0
      *(p++) = len;
2353
0
      p += len;
2354
0
    }
2355
0
      *p = OPTION_END;
2356
0
    }
2357
2358
0
  return ret;
2359
0
}
2360
2361
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid, const char *pxevendor)
2362
0
{
2363
0
  unsigned char *p;
2364
2365
0
  if (!pxevendor)
2366
0
    pxevendor="PXEClient";
2367
0
  option_put_string(mess, end, OPTION_VENDOR_ID, pxevendor, 0);
2368
0
  if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
2369
0
    memcpy(p, uuid, 17);
2370
0
}
2371
2372
static int prune_vendor_opts(struct dhcp_netid *netid)
2373
0
{
2374
0
  int force = 0;
2375
0
  struct dhcp_opt *opt;
2376
2377
  /* prune vendor-encapsulated options based on netid, and look if we're forcing them to be sent */
2378
0
  for (opt = daemon->dhcp_opts; opt; opt = opt->next)
2379
0
    if (opt->flags & DHOPT_VENDOR_MATCH)
2380
0
      {
2381
0
  if (!match_netid(opt->netid, netid, 1))
2382
0
    opt->flags &= ~DHOPT_VENDOR_MATCH;
2383
0
  else if (opt->flags & DHOPT_FORCE)
2384
0
    force = 1;
2385
0
      }
2386
0
  return force;
2387
0
}
2388
2389
2390
/* Many UEFI PXE implementations have badly broken menu code.
2391
   If there's exactly one relevant menu item, we abandon the menu system,
2392
   and jamb the data direct into the DHCP file, siaddr and sname fields.
2393
   Note that in this case, we have to assume that layer zero would be requested
2394
   by the client PXE stack. */
2395
static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe)
2396
0
{
2397
0
  struct pxe_service *service, *found;
2398
2399
  /* Only workaround UEFI archs. */
2400
0
  if (pxe_arch < 6)
2401
0
    return 0;
2402
  
2403
0
  for (found = NULL, service = daemon->pxe_services; service; service = service->next)
2404
0
    if (pxe_arch == service->CSA && service->basename && match_netid(service->netid, netid, 1))
2405
0
      {
2406
0
  if (found)
2407
0
    return 0; /* More than one relevant menu item */
2408
    
2409
0
  found = service;
2410
0
      }
2411
2412
0
  if (!found)
2413
0
    return 0; /* No relevant menu items. */
2414
  
2415
0
  if (!pxe)
2416
0
     return 1;
2417
  
2418
0
  if (found->sname)
2419
0
    {
2420
0
      mess->siaddr = a_record_from_hosts(found->sname, now);
2421
0
      snprintf((char *)mess->sname, sizeof(mess->sname), "%s", found->sname);
2422
0
    }
2423
0
  else 
2424
0
    {
2425
0
      if (found->server.s_addr != 0)
2426
0
  mess->siaddr = found->server; 
2427
0
      else
2428
0
  mess->siaddr = local;
2429
  
2430
0
      inet_ntop(AF_INET, &mess->siaddr, (char *)mess->sname, INET_ADDRSTRLEN);
2431
0
    }
2432
  
2433
0
  if (found->basename)
2434
0
    snprintf((char *)mess->file, sizeof(mess->file), 
2435
0
       strchr(found->basename, '.') ? "%s" : "%s.0", found->basename);
2436
  
2437
0
  return 1;
2438
0
}
2439
2440
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now)
2441
0
{
2442
0
#define NUM_OPTS 4  
2443
2444
0
  unsigned  char *p, *q;
2445
0
  struct pxe_service *service;
2446
0
  static struct dhcp_opt *o, *ret;
2447
0
  int i, j = NUM_OPTS - 1;
2448
0
  struct in_addr boot_server;
2449
  
2450
  /* We pass back references to these, hence they are declared static */
2451
0
  static unsigned char discovery_control;
2452
0
  static unsigned char fake_prompt[] = { 0, 'P', 'X', 'E' }; 
2453
0
  static struct dhcp_opt *fake_opts = NULL;
2454
  
2455
  /* Disable multicast, since we don't support it, and broadcast
2456
     unless we need it */
2457
0
  discovery_control = 3;
2458
  
2459
0
  ret = daemon->dhcp_opts;
2460
  
2461
0
  if (!fake_opts && !(fake_opts = whine_malloc(NUM_OPTS * sizeof(struct dhcp_opt))))
2462
0
    return ret;
2463
2464
0
  for (i = 0; i < NUM_OPTS; i++)
2465
0
    {
2466
0
      fake_opts[i].flags = DHOPT_VENDOR_MATCH;
2467
0
      fake_opts[i].netid = NULL;
2468
0
      fake_opts[i].next = i == (NUM_OPTS - 1) ? ret : &fake_opts[i+1];
2469
0
    }
2470
  
2471
  /* create the data for the PXE_MENU and PXE_SERVERS options. */
2472
0
  p = (unsigned char *)daemon->dhcp_buff;
2473
0
  q = (unsigned char *)daemon->dhcp_buff3;
2474
2475
0
  for (i = 0, service = daemon->pxe_services; service; service = service->next)
2476
0
    if (pxe_arch == service->CSA && match_netid(service->netid, netid, 1))
2477
0
      {
2478
0
  size_t len = strlen(service->menu);
2479
  /* opt 43 max size is 255. encapsulated option has type and length
2480
     bytes, so its max size is 253. */
2481
0
  if (p - (unsigned char *)daemon->dhcp_buff + len + 3 < 253)
2482
0
    {
2483
0
      *(p++) = service->type >> 8;
2484
0
      *(p++) = service->type;
2485
0
      *(p++) = len;
2486
0
      memcpy(p, service->menu, len);
2487
0
      p += len;
2488
0
      i++;
2489
0
    }
2490
0
  else
2491
0
    {
2492
0
    toobig:
2493
0
      my_syslog(MS_DHCP | LOG_ERR, _("PXE menu too large"));
2494
0
      return daemon->dhcp_opts;
2495
0
    }
2496
  
2497
0
  boot_server = service->basename ? local : 
2498
0
    (service->sname ? a_record_from_hosts(service->sname, now) : service->server);
2499
  
2500
0
  if (boot_server.s_addr != 0)
2501
0
    {
2502
0
      if (q - (unsigned char *)daemon->dhcp_buff3 + 3 + INADDRSZ >= 253)
2503
0
        goto toobig;
2504
      
2505
      /* Boot service with known address - give it */
2506
0
      *(q++) = service->type >> 8;
2507
0
      *(q++) = service->type;
2508
0
      *(q++) = 1;
2509
      /* dest misaligned */
2510
0
      memcpy(q, &boot_server.s_addr, INADDRSZ);
2511
0
      q += INADDRSZ;
2512
0
    }
2513
0
  else if (service->type != 0)
2514
    /* We don't know the server for a service type, so we'll
2515
       allow the client to broadcast for it */
2516
0
    discovery_control = 2;
2517
0
      }
2518
2519
  /* if no prompt, wait forever if there's a choice */
2520
0
  fake_prompt[0] = (i > 1) ? 255 : 0;
2521
  
2522
0
  if (i == 0)
2523
0
    discovery_control = 8; /* no menu - just use use mess->filename */
2524
0
  else
2525
0
    {
2526
0
      ret = &fake_opts[j--];
2527
0
      ret->len = p - (unsigned char *)daemon->dhcp_buff;
2528
0
      ret->val = (unsigned char *)daemon->dhcp_buff;
2529
0
      ret->opt = SUBOPT_PXE_MENU;
2530
2531
0
      if (q - (unsigned char *)daemon->dhcp_buff3 != 0)
2532
0
  {
2533
0
    ret = &fake_opts[j--]; 
2534
0
    ret->len = q - (unsigned char *)daemon->dhcp_buff3;
2535
0
    ret->val = (unsigned char *)daemon->dhcp_buff3;
2536
0
    ret->opt = SUBOPT_PXE_SERVERS;
2537
0
  }
2538
0
    }
2539
2540
0
  for (o = daemon->dhcp_opts; o; o = o->next)
2541
0
    if ((o->flags & DHOPT_VENDOR_MATCH) && o->opt == SUBOPT_PXE_MENU_PROMPT)
2542
0
      break;
2543
  
2544
0
  if (!o)
2545
0
    {
2546
0
      ret = &fake_opts[j--]; 
2547
0
      ret->len = sizeof(fake_prompt);
2548
0
      ret->val = fake_prompt;
2549
0
      ret->opt = SUBOPT_PXE_MENU_PROMPT;
2550
0
    }
2551
  
2552
0
  ret = &fake_opts[j--]; 
2553
0
  ret->len = 1;
2554
0
  ret->opt = SUBOPT_PXE_DISCOVERY;
2555
0
  ret->val= &discovery_control;
2556
 
2557
0
  return ret;
2558
0
}
2559
  
2560
static void clear_packet(struct dhcp_packet *mess, unsigned char *end)
2561
0
{
2562
0
  memset(mess->sname, 0, sizeof(mess->sname));
2563
0
  memset(mess->file, 0, sizeof(mess->file));
2564
0
  memset(&mess->options[0] + sizeof(u32), 0, end - (&mess->options[0] + sizeof(u32)));
2565
0
  mess->siaddr.s_addr = 0;
2566
0
}
2567
2568
struct dhcp_boot *find_boot(struct dhcp_netid *netid)
2569
0
{
2570
0
  struct dhcp_boot *boot;
2571
2572
  /* decide which dhcp-boot option we're using */
2573
0
  for (boot = daemon->boot_config; boot; boot = boot->next)
2574
0
    if (match_netid(boot->netid, netid, 0))
2575
0
      break;
2576
0
  if (!boot)
2577
    /* No match, look for one without a netid */
2578
0
    for (boot = daemon->boot_config; boot; boot = boot->next)
2579
0
      if (match_netid(boot->netid, netid, 1))
2580
0
  break;
2581
2582
0
  return boot;
2583
0
}
2584
2585
static int is_pxe_client(struct dhcp_packet *mess, size_t sz, const char **pxe_vendor)
2586
0
{
2587
0
  const unsigned char *opt = NULL;
2588
0
  ssize_t conf_len = 0;
2589
0
  const struct dhcp_pxe_vendor *conf = daemon->dhcp_pxe_vendors;
2590
0
  opt = option_find(mess, sz, OPTION_VENDOR_ID, 0);
2591
0
  if (!opt) 
2592
0
    return 0;
2593
0
  for (; conf; conf = conf->next)
2594
0
    {
2595
0
      conf_len = strlen(conf->data);
2596
0
      if (option_len(opt) < conf_len)
2597
0
        continue;
2598
0
      if (strncmp(option_ptr(opt, 0), conf->data, conf_len) == 0)
2599
0
        {
2600
0
          if (pxe_vendor)
2601
0
            *pxe_vendor = conf->data;
2602
0
          return 1;
2603
0
        }
2604
0
    }
2605
0
  return 0;
2606
0
}
2607
2608
static void do_options(struct dhcp_context *context,
2609
           struct dhcp_packet *mess,
2610
           unsigned char *end, 
2611
           unsigned char *req_options,
2612
           char *hostname, 
2613
           char *domain,
2614
           struct dhcp_netid *netid,
2615
           struct in_addr subnet_addr,
2616
           unsigned char fqdn_flags,
2617
           int null_term, int pxe_arch,
2618
           unsigned char *uuid,
2619
           int vendor_class_len,
2620
           time_t now,
2621
           unsigned int lease_time,
2622
           unsigned short fuzz,
2623
           const char *pxevendor,
2624
           int leasequery)
2625
0
{
2626
0
  struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
2627
0
  struct dhcp_boot *boot;
2628
0
  unsigned char *p;
2629
0
  int i, len, force_encap = 0;
2630
0
  unsigned char f0 = 0, s0 = 0;
2631
0
  int done_file = 0, done_server = 0;
2632
0
  int done_vendor_class = 0;
2633
0
  struct dhcp_netid *tagif;
2634
0
  struct dhcp_netid_list *id_list;
2635
2636
  /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
2637
0
  if (context)
2638
0
    context->netid.next = NULL;
2639
0
  tagif = option_filter(netid, context && context->netid.net ? &context->netid : NULL, config_opts, pxe_arch != -1);
2640
  
2641
  /* logging */
2642
0
  if (option_bool(OPT_LOG_OPTS) && req_options)
2643
0
    {
2644
0
      char *q = daemon->namebuff;
2645
0
      for (i = 0; req_options[i] != OPTION_END; i++)
2646
0
  {
2647
0
    char *s = option_string(AF_INET, req_options[i], NULL, 0, NULL, 0);
2648
0
    q += snprintf(q, MAXDNAMESTR - (q - daemon->namebuff),
2649
0
      "%d%s%s%s", 
2650
0
      req_options[i],
2651
0
      strlen(s) != 0 ? ":" : "",
2652
0
      s, 
2653
0
      req_options[i+1] == OPTION_END ? "" : ", ");
2654
0
    if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
2655
0
      {
2656
0
        q = daemon->namebuff;
2657
0
        my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), ntohl(mess->xid), daemon->namebuff);
2658
0
      }
2659
0
  }
2660
0
    }
2661
      
2662
0
  if (!leasequery)
2663
0
    {
2664
0
      for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
2665
0
  if ((!id_list->list) || match_netid(id_list->list, netid, 0))
2666
0
    break;
2667
0
      if (id_list)
2668
0
  mess->flags |= htons(0x8000); /* force broadcast */
2669
      
2670
0
      if (context)
2671
0
  mess->siaddr = context->local;
2672
     
2673
      /* See if we can send the boot stuff as options.
2674
   To do this we need a requested option list, BOOTP
2675
   and very old DHCP clients won't have this, we also 
2676
   provide a manual option to disable it.
2677
   Some PXE ROMs have bugs (surprise!) and need zero-terminated 
2678
   names, so we always send those.  */
2679
0
      if ((boot = find_boot(tagif)))
2680
0
  {
2681
0
    if (boot->sname)
2682
0
      {   
2683
0
        if (!option_bool(OPT_NO_OVERRIDE) &&
2684
0
      req_options && 
2685
0
      in_list(req_options, OPTION_SNAME))
2686
0
    option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
2687
0
        else
2688
0
    safe_strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname));
2689
0
      }
2690
    
2691
0
    if (boot->file)
2692
0
      {
2693
0
        if (!option_bool(OPT_NO_OVERRIDE) &&
2694
0
      req_options && 
2695
0
      in_list(req_options, OPTION_FILENAME))
2696
0
    option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
2697
0
        else
2698
0
    safe_strncpy((char *)mess->file, boot->file, sizeof(mess->file));
2699
0
      }
2700
    
2701
0
    if (boot->next_server.s_addr) 
2702
0
      mess->siaddr = boot->next_server;
2703
0
    else if (boot->tftp_sname)
2704
0
      mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
2705
0
  }
2706
0
      else
2707
  /* Use the values of the relevant options if no dhcp-boot given and
2708
     they're not explicitly asked for as options. OPTION_END is used
2709
     as an internal way to specify siaddr without using dhcp-boot, for use in
2710
     dhcp-optsfile. */
2711
0
  {
2712
0
    if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
2713
0
        (opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
2714
0
      {
2715
0
        safe_strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file));
2716
0
        done_file = 1;
2717
0
      }
2718
    
2719
0
    if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
2720
0
        (opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
2721
0
      {
2722
0
        safe_strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname));
2723
0
        done_server = 1;
2724
0
      }
2725
    
2726
0
    if ((opt = option_find2(OPTION_END)))
2727
0
      mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr; 
2728
0
  }
2729
0
    }
2730
        
2731
  /* We don't want to do option-overload for BOOTP, so make the file and sname
2732
     fields look like they are in use, even when they aren't. This gets restored
2733
     at the end of this function. */
2734
2735
0
  if (!req_options || option_bool(OPT_NO_OVERRIDE))
2736
0
    {
2737
0
      f0 = mess->file[0];
2738
0
      mess->file[0] = 1;
2739
0
      s0 = mess->sname[0];
2740
0
      mess->sname[0] = 1;
2741
0
    }
2742
      
2743
  /* At this point, if mess->sname or mess->file are zeroed, they are available
2744
     for option overload, reserve space for the overload option. */
2745
0
  if (mess->file[0] == 0 || mess->sname[0] == 0)
2746
0
    end -= 3;
2747
2748
  /* rfc3011 says this doesn't need to be in the requested options list. */
2749
0
  if (!leasequery && subnet_addr.s_addr)
2750
0
    option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
2751
   
2752
0
  if (lease_time != 0xffffffff)
2753
0
    { 
2754
0
      unsigned int t1val = lease_time/2; 
2755
0
      unsigned int t2val = (lease_time*7)/8;
2756
0
      unsigned int hval;
2757
      
2758
      /* If set by user, sanity check, so not longer than lease. */
2759
0
      if ((opt = option_find2(OPTION_T1)))
2760
0
  {
2761
0
    hval = ntohl(*((unsigned int *)opt->val));
2762
0
    if (hval < lease_time && hval > 2)
2763
0
      t1val = hval;
2764
0
  }
2765
2766
0
       if ((opt = option_find2(OPTION_T2)))
2767
0
  {
2768
0
    hval = ntohl(*((unsigned int *)opt->val));
2769
0
    if (hval < lease_time && hval > 2)
2770
0
      t2val = hval;
2771
0
  }
2772
          
2773
       /* ensure T1 is still < T2 */
2774
0
       if (t2val <= t1val)
2775
0
   t1val = t2val - 1; 
2776
2777
0
       while (fuzz > (t1val/8))
2778
0
   fuzz = fuzz/2;
2779
   
2780
0
       t1val -= fuzz;
2781
0
       t2val -= fuzz;
2782
       
2783
0
       option_put(mess, end, OPTION_T1, 4, t1val);
2784
0
       option_put(mess, end, OPTION_T2, 4, t2val);
2785
0
    }
2786
2787
  /* replies to DHCPINFORM may not have a valid context */
2788
0
  if (context)
2789
0
    {
2790
      /* Netmask and broadcast always sent, except leasequery. */
2791
0
      if (!option_find2(OPTION_NETMASK) &&
2792
0
    (!leasequery || in_list(req_options, OPTION_NETMASK)))
2793
0
  option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
2794
      
2795
      /* May not have a "guessed" broadcast address if we got no packets via a relay
2796
   from this net yet (ie just unicast renewals after a restart */
2797
0
      if (context->broadcast.s_addr &&
2798
0
    !option_find2(OPTION_BROADCAST) &&
2799
0
    (!leasequery || in_list(req_options, OPTION_BROADCAST)))
2800
0
      option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
2801
      
2802
      /* Same comments as broadcast apply, and also may not be able to get a sensible
2803
   default when using subnet select.  User must configure by steam in that case. */
2804
0
      if (context->router.s_addr &&
2805
0
    in_list(req_options, OPTION_ROUTER) &&
2806
0
    !option_find2(OPTION_ROUTER))
2807
0
  option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
2808
      
2809
0
      if (daemon->port == NAMESERVER_PORT &&
2810
0
    in_list(req_options, OPTION_DNSSERVER) &&
2811
0
    !option_find2(OPTION_DNSSERVER))
2812
0
  option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
2813
0
    }
2814
2815
0
  if (domain && in_list(req_options, OPTION_DOMAINNAME) && 
2816
0
      !option_find2(OPTION_DOMAINNAME))
2817
0
    option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
2818
 
2819
  /* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
2820
0
  if (hostname)
2821
0
    {
2822
0
      if (in_list(req_options, OPTION_HOSTNAME) &&
2823
0
    !option_find2(OPTION_HOSTNAME))
2824
0
  option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
2825
      
2826
0
      if (fqdn_flags != 0)
2827
0
  {
2828
0
    len = strlen(hostname) + 3;
2829
    
2830
0
    if (fqdn_flags & 0x04)
2831
0
      len += 2;
2832
0
    else if (null_term)
2833
0
      len++;
2834
2835
0
    if (domain)
2836
0
      len += strlen(domain) + 1;
2837
0
    else if (fqdn_flags & 0x04)
2838
0
      len--;
2839
2840
0
    if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
2841
0
      {
2842
0
        *(p++) = fqdn_flags & 0x0f; /* MBZ bits to zero */ 
2843
0
        *(p++) = 255;
2844
0
        *(p++) = 255;
2845
2846
0
        if (fqdn_flags & 0x04)
2847
0
    {
2848
0
      p = do_rfc1035_name(p, hostname, NULL);
2849
0
      if (domain)
2850
0
        {
2851
0
          p = do_rfc1035_name(p, domain, NULL);
2852
0
          *p++ = 0;
2853
0
        }
2854
0
    }
2855
0
        else
2856
0
    {
2857
0
      memcpy(p, hostname, strlen(hostname));
2858
0
      p += strlen(hostname);
2859
0
      if (domain)
2860
0
        {
2861
0
          *(p++) = '.';
2862
0
          memcpy(p, domain, strlen(domain));
2863
0
          p += strlen(domain);
2864
0
        }
2865
0
      if (null_term)
2866
0
        *(p++) = 0;
2867
0
    }
2868
0
      }
2869
0
  }
2870
0
    }      
2871
2872
0
  for (opt = config_opts; opt; opt = opt->next)
2873
0
    {
2874
0
      int optno = opt->opt;
2875
2876
      /* netids match and not encapsulated? */
2877
0
      if (!(opt->flags & DHOPT_TAGOK))
2878
0
  continue;
2879
      
2880
      /* was it asked for, or are we sending it anyway? */
2881
0
      if ((!(opt->flags & DHOPT_FORCE) || leasequery) && !in_list(req_options, optno))
2882
0
  continue;
2883
      
2884
      /* prohibit some used-internally options. T1 and T2 already handled. */
2885
0
      if (optno == OPTION_CLIENT_FQDN ||
2886
0
    optno == OPTION_MAXMESSAGE ||
2887
0
    optno == OPTION_OVERLOAD ||
2888
0
    optno == OPTION_PAD ||
2889
0
    optno == OPTION_END ||
2890
0
    optno == OPTION_T1 ||
2891
0
    optno == OPTION_T2)
2892
0
  continue;
2893
2894
0
      if (optno == OPTION_SNAME && done_server)
2895
0
  continue;
2896
2897
0
      if (optno == OPTION_FILENAME && done_file)
2898
0
  continue;
2899
      
2900
      /* For the options we have default values on
2901
   dhc-option=<optionno> means "don't include this option"
2902
   not "include a zero-length option" */
2903
0
      if (opt->len == 0 && 
2904
0
    (optno == OPTION_NETMASK ||
2905
0
     optno == OPTION_BROADCAST ||
2906
0
     optno == OPTION_ROUTER ||
2907
0
     optno == OPTION_DNSSERVER || 
2908
0
     optno == OPTION_DOMAINNAME ||
2909
0
     optno == OPTION_HOSTNAME))
2910
0
  continue;
2911
2912
      /* vendor-class comes from elsewhere for PXE */
2913
0
      if (pxe_arch != -1 && optno == OPTION_VENDOR_ID)
2914
0
  continue;
2915
      
2916
      /* always force null-term for filename and servername - buggy PXE again. */
2917
0
      len = do_opt(opt, NULL, context, 
2918
0
       (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
2919
2920
0
      if ((p = free_space(mess, end, optno, len)))
2921
0
  {
2922
0
    do_opt(opt, p, context, 
2923
0
     (optno == OPTION_SNAME || optno == OPTION_FILENAME) ? 1 : null_term);
2924
    
2925
    /* If we send a vendor-id, revisit which vendor-ops we consider 
2926
       it appropriate to send. */
2927
0
    if (optno == OPTION_VENDOR_ID)
2928
0
      {
2929
0
        match_vendor_opts(p - 2, config_opts);
2930
0
        done_vendor_class = 1;
2931
0
      }
2932
0
  }  
2933
0
    }
2934
2935
  /* encapsulated options. */
2936
0
  handle_encap(mess, end, req_options, null_term, tagif, pxe_arch != 1);
2937
  
2938
0
  force_encap = prune_vendor_opts(tagif);
2939
    
2940
0
  if (context && pxe_arch != -1)
2941
0
    {
2942
0
      pxe_misc(mess, end, uuid, pxevendor);
2943
0
      if (!pxe_uefi_workaround(pxe_arch, tagif, mess, context->local, now, 0))
2944
0
  config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
2945
0
    }
2946
2947
0
  if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT) || in_list(req_options, OPTION_VENDOR_ID)) &&
2948
0
      (leasequery || do_encap_opts(config_opts, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, null_term)) && 
2949
0
      pxe_arch == -1 && !done_vendor_class && vendor_class_len != 0 &&
2950
0
      (p = free_space(mess, end, OPTION_VENDOR_ID, vendor_class_len)))
2951
    /* If we send vendor encapsulated options, and haven't already sent option 60,
2952
       echo back the value we got from the client. */
2953
0
    memcpy(p, daemon->dhcp_buff3, vendor_class_len);      
2954
   
2955
   /* restore BOOTP anti-overload hack */
2956
0
  if (!req_options || option_bool(OPT_NO_OVERRIDE))
2957
0
    {
2958
0
      mess->file[0] = f0;
2959
0
      mess->sname[0] = s0;
2960
0
    }
2961
0
}
2962
2963
static void handle_encap(struct dhcp_packet *mess, unsigned char *end, unsigned char *req_options,
2964
       int null_term, struct dhcp_netid *tagif, int pxemode)
2965
0
{
2966
  /* Send options to be encapsulated in arbitrary options, 
2967
     eg dhcp-option=encap:172,17,.......
2968
     Also handle vendor-identifying vendor-encapsulated options,
2969
     dhcp-option = vi-encap:13,17,.......
2970
     The may be more that one "outer" to do, so group
2971
     all the options which match each outer in turn. */
2972
2973
0
  struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
2974
0
  unsigned char *p;
2975
0
  int len;
2976
2977
0
  for (opt = config_opts; opt; opt = opt->next)
2978
0
    opt->flags &= ~DHOPT_ENCAP_DONE;
2979
  
2980
0
  for (opt = config_opts; opt; opt = opt->next)
2981
0
    {
2982
0
      int flags;
2983
2984
0
      if ((flags = (opt->flags & (DHOPT_ENCAPSULATE | DHOPT_RFC3925))))
2985
0
  {
2986
0
    int found = 0;
2987
0
    struct dhcp_opt *o;
2988
2989
0
    if (opt->flags & DHOPT_ENCAP_DONE)
2990
0
      continue;
2991
2992
0
    for (len = 0, o = config_opts; o; o = o->next)
2993
0
      {
2994
0
        int outer = flags & DHOPT_ENCAPSULATE ? o->u.encap : OPTION_VENDOR_IDENT_OPT;
2995
2996
0
        o->flags &= ~DHOPT_ENCAP_MATCH;
2997
        
2998
0
        if (!(o->flags & flags) || opt->u.encap != o->u.encap)
2999
0
    continue;
3000
        
3001
0
        o->flags |= DHOPT_ENCAP_DONE;
3002
0
        if (match_netid(o->netid, tagif, 1) &&
3003
0
      pxe_ok(o, pxemode) &&
3004
0
      ((o->flags & DHOPT_FORCE) || in_list(req_options, outer)))
3005
0
    {
3006
0
      o->flags |= DHOPT_ENCAP_MATCH;
3007
0
      found = 1;
3008
0
      len += do_opt(o, NULL, NULL, 0) + 2;
3009
0
    }
3010
0
      } 
3011
    
3012
0
    if (found)
3013
0
      { 
3014
0
        if (flags & DHOPT_ENCAPSULATE)
3015
0
    do_encap_opts(config_opts, opt->u.encap, DHOPT_ENCAP_MATCH, mess, end, null_term);
3016
0
        else if (len > 250)
3017
0
    my_syslog(MS_DHCP | LOG_WARNING, _("cannot send RFC3925 option: too many options for enterprise number %d"), opt->u.encap);
3018
0
        else if ((p = free_space(mess, end,  OPTION_VENDOR_IDENT_OPT, len + 5)))
3019
0
    {
3020
0
      int swap_ent = htonl(opt->u.encap);
3021
0
      memcpy(p, &swap_ent, 4);
3022
0
      p += 4;
3023
0
      *(p++) = len;
3024
0
      for (o = config_opts; o; o = o->next)
3025
0
        if (o->flags & DHOPT_ENCAP_MATCH)
3026
0
          {
3027
0
      len = do_opt(o, p + 2, NULL, 0);
3028
0
      *(p++) = o->opt;
3029
0
      *(p++) = len;
3030
0
      p += len;
3031
0
          }     
3032
0
    }
3033
0
      }
3034
0
  }
3035
0
    }      
3036
0
}
3037
3038
static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid)
3039
0
{
3040
0
  struct delay_config *delay_conf;
3041
  
3042
  /* Decide which delay_config option we're using */
3043
0
  for (delay_conf = daemon->delay_conf; delay_conf; delay_conf = delay_conf->next)
3044
0
    if (match_netid(delay_conf->netid, netid, 0))
3045
0
      break;
3046
  
3047
0
  if (!delay_conf)
3048
    /* No match, look for one without a netid */
3049
0
    for (delay_conf = daemon->delay_conf; delay_conf; delay_conf = delay_conf->next)
3050
0
      if (match_netid(delay_conf->netid, netid, 1))
3051
0
        break;
3052
3053
0
  if (delay_conf)
3054
0
    {
3055
0
      if (!option_bool(OPT_QUIET_DHCP))
3056
0
  my_syslog(MS_DHCP | LOG_INFO, _("%u reply delay: %d"), ntohl(xid), delay_conf->delay);
3057
0
      delay_dhcp(recvtime, delay_conf->delay, -1, 0, 0);
3058
0
    }
3059
0
}
3060
3061
void relay_upstream4(struct in_addr iface_addr, int iface_index, struct dhcp_packet *mess, size_t sz, int unicast)
3062
0
{
3063
0
  struct in_addr giaddr = mess->giaddr;
3064
0
  u8 hops = mess->hops;
3065
0
  struct dhcp_relay *relay;
3066
0
  size_t orig_sz = sz;
3067
0
  unsigned char *endopt = NULL;
3068
    
3069
0
  if (mess->op != BOOTREQUEST || (mess->hops++) > 20)
3070
0
    return;
3071
  
3072
0
  for (relay = daemon->relay4; relay; relay = relay->next)
3073
0
    {
3074
0
      union mysockaddr to;
3075
0
      union all_addr from;
3076
0
      struct ifreq ifr;
3077
3078
      /* restore orig packet */
3079
0
      mess->giaddr = giaddr;
3080
0
      if (endopt)
3081
0
  *endopt = OPTION_END;
3082
0
      sz = orig_sz;
3083
3084
0
      if (relay->interface)
3085
0
  {
3086
0
    safe_strncpy(ifr.ifr_name, relay->interface, IF_NAMESIZE);
3087
0
    ifr.ifr_addr.sa_family = AF_INET;
3088
0
  }
3089
      
3090
0
      if (!relay->split_mode && relay->iface_index && relay->iface_index == iface_index)
3091
0
  {
3092
    /* already gatewayed ? */
3093
0
    if (giaddr.s_addr)
3094
0
      {
3095
        /* if so check if by us, to stomp on loops. */
3096
0
        if (giaddr.s_addr == relay->local.addr4.s_addr)
3097
0
    continue;
3098
0
      }
3099
0
    else
3100
      /* plug in our address */
3101
0
      mess->giaddr = relay->local.addr4;
3102
    
3103
0
    from.addr4 = relay->local.addr4;
3104
0
  }
3105
0
      else if (relay->split_mode && relay->local.addr4.s_addr == iface_addr.s_addr)
3106
0
  {
3107
    /* Split mode. We put our address on the server-facing interface
3108
       or a directly specified third address into giaddr for the server to talk back to us on.
3109
       
3110
       Our address on client-facing interface goes into agent-id subnet-selector subopt,
3111
       so that the server allocates the correct address. We also send a
3112
       remote-id with the interface on which the request arrived,
3113
       so that we can send the reply back the same way. */
3114
0
    unsigned int net_index = htonl(iface_index);
3115
    
3116
0
    if (relay->interface)
3117
0
      {
3118
        /* get our address on the server-facing interface. */
3119
0
        if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
3120
0
    {
3121
0
      my_syslog(MS_DHCP | LOG_ERR, _("Cannot send to server via interface %s: %s"), relay->interface, strerror(errno));
3122
0
      continue;
3123
0
    }
3124
        
3125
0
        relay->uplink.addr4 = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
3126
0
      }
3127
    
3128
    /* already gatewayed ? */
3129
0
    if (giaddr.s_addr)
3130
0
      {
3131
        /* if so check if by us, to stomp on loops. */
3132
0
        if (giaddr.s_addr == relay->uplink.addr4.s_addr)
3133
0
    continue;
3134
0
      }
3135
0
    else
3136
0
      {
3137
        /* giaddr is our address on the outgoing interface in split mode. */
3138
0
        mess->giaddr = relay->uplink.addr4;
3139
        
3140
0
        if (!endopt)
3141
0
    {
3142
      /* Add an RFC3026 relay agent information option (2 bytes) at the very end of the options.
3143
         Said option to contain a RFC 3527 link selection sub option (6 bytes) and
3144
         RFC 5017 serverid-override option (6 bytes) and RFC5010 flags (3 bytes) and
3145
         an RFC3046 remote-id which holds an interface index (6 bytes)
3146
         
3147
         New END option is a 24th byte, so we need 24 bytes free.
3148
         We only need to do this once, and poke the address/interface/flags into the same place each time. */
3149
      
3150
0
      if (!(endopt = option_find1((&mess->options[0] + sizeof(u32)), ((unsigned char *)mess) + sz, OPTION_END, 0)) ||
3151
0
          (endopt + 24 > (unsigned char *)(mess + 1)))
3152
0
        continue;
3153
      
3154
0
      endopt[1] = 21; /* length */
3155
0
      endopt[2] = SUBOPT_SUBNET_SELECT;
3156
0
      endopt[3] = 4; /* length */
3157
0
      endopt[8] = SUBOPT_SERVER_OR;
3158
0
      endopt[9] = 4;
3159
0
      endopt[14] = SUBOPT_FLAGS;
3160
0
      endopt[15] = 1; /* length */
3161
0
      endopt[17] = SUBOPT_REMOTE_ID;
3162
0
      endopt[18] = 4; /* length */
3163
0
      endopt[23] = OPTION_END;
3164
0
      sz = (endopt - (unsigned char *)mess) + 24;
3165
0
    }
3166
        
3167
        /* IP address is already in network byte order */
3168
0
        memcpy(&endopt[4], &relay->local.addr4.s_addr, INADDRSZ);
3169
0
        memcpy(&endopt[10], &relay->local.addr4.s_addr, INADDRSZ);
3170
0
        endopt[16] = unicast ? 0x80 : 0x00;
3171
0
        memcpy(&endopt[19], &net_index, 4);
3172
0
        endopt[0] = OPTION_AGENT_ID;
3173
0
      }
3174
    
3175
0
    from.addr4 = relay->uplink.addr4;
3176
0
  }
3177
0
      else
3178
0
  continue;
3179
  
3180
0
      to.sa.sa_family = AF_INET;
3181
0
      to.in.sin_addr = relay->server.addr4;
3182
0
      to.in.sin_port = htons(relay->port);
3183
#ifdef HAVE_SOCKADDR_SA_LEN
3184
      to.in.sin_len = sizeof(struct sockaddr_in);
3185
#endif
3186
      
3187
      /* Broadcasting to server. */
3188
0
      if (relay->server.addr4.s_addr == 0)
3189
0
  {
3190
0
    if (ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) == -1)
3191
0
      {
3192
0
        my_syslog(MS_DHCP | LOG_ERR, _("Cannot broadcast DHCP relay via interface %s: %s"), relay->interface, strerror(errno));
3193
0
        continue;
3194
0
      }
3195
    
3196
0
    to.in.sin_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
3197
0
  }
3198
      
3199
0
#ifdef HAVE_DUMPFILE
3200
0
      {
3201
0
  union mysockaddr fromsock;
3202
0
  fromsock.in.sin_port = htons(daemon->dhcp_server_port);
3203
0
  fromsock.in.sin_addr = from.addr4;
3204
0
  fromsock.sa.sa_family = AF_INET;
3205
  
3206
0
  dump_packet_udp(DUMP_DHCP, (void *)mess, sz, &fromsock, &to, -1);
3207
0
      }
3208
0
#endif
3209
      
3210
0
      send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
3211
      
3212
0
      if (option_bool(OPT_LOG_OPTS))
3213
0
  {
3214
0
    inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
3215
0
    if (relay->server.addr4.s_addr == 0)
3216
0
      snprintf(daemon->dhcp_buff2, DHCP_BUFF_SZ, _("broadcast via %s"), relay->interface);
3217
0
    else
3218
0
      inet_ntop(AF_INET, &relay->server.addr4, daemon->dhcp_buff2, DHCP_BUFF_SZ);
3219
0
    my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay at %s -> %s"), daemon->addrbuff, daemon->dhcp_buff2);
3220
0
  }
3221
0
    }
3222
  
3223
  /* restore in case of a local reply. */
3224
0
  mess->hops = hops;
3225
0
  mess->giaddr = giaddr;
3226
0
  if (endopt)
3227
0
    *endopt = OPTION_END;
3228
0
}
3229
3230
unsigned int relay_reply4(struct dhcp_packet *mess, size_t sz, char *arrival_interface)
3231
0
{
3232
0
  struct dhcp_relay *relay;
3233
    
3234
0
  if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
3235
0
    return 0;
3236
3237
0
  for (relay = daemon->relay4; relay; relay = relay->next)
3238
0
    {
3239
0
      unsigned int return_iface = 0;
3240
3241
0
      if (relay->split_mode)
3242
0
  {
3243
0
    unsigned char *opt, *sopt;
3244
    
3245
    /* giaddr is our address on the returning interface in split mode. */
3246
0
    if (mess->giaddr.s_addr == relay->uplink.addr4.s_addr &&
3247
0
        (opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
3248
0
      {
3249
0
        if ((sopt = option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_REMOTE_ID, sizeof(unsigned int))))
3250
0
    return_iface = option_uint(sopt, 0, sizeof(unsigned int));
3251
3252
        /* delete agent info before return RFC 3046 para 2.1 */
3253
0
        *opt = OPTION_END;
3254
0
        memset(opt + 1, 0, option_len(opt) + 1);
3255
0
      }
3256
0
  }
3257
0
      else if (mess->giaddr.s_addr == relay->local.addr4.s_addr)
3258
0
  return_iface = relay->iface_index;
3259
      
3260
0
      if (return_iface && (!relay->interface || wildcard_match(relay->interface, arrival_interface)))
3261
0
  return return_iface;
3262
0
    }
3263
  
3264
0
  return 0;  
3265
0
}     
3266
3267
3268
#endif /* HAVE_DHCP */