Annotation of embedaddon/dnsmasq/src/rfc3315.c, revision 1.1.1.5
1.1.1.5 ! misho 1: /* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
1.1 misho 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:
18: #include "dnsmasq.h"
19:
20: #ifdef HAVE_DHCP6
21:
22: struct state {
23: unsigned char *clid;
1.1.1.4 misho 24: int clid_len, ia_type, interface, hostname_auth, lease_allocate;
1.1 misho 25: char *client_hostname, *hostname, *domain, *send_domain;
26: struct dhcp_context *context;
1.1.1.2 misho 27: struct in6_addr *link_address, *fallback, *ll_addr, *ula_addr;
1.1.1.4 misho 28: unsigned int xid, fqdn_flags, iaid;
1.1 misho 29: char *iface_name;
30: void *packet_options, *end;
31: struct dhcp_netid *tags, *context_tags;
1.1.1.2 misho 32: unsigned char mac[DHCP_CHADDR_MAX];
33: unsigned int mac_len, mac_type;
1.1 misho 34: };
35:
1.1.1.5 ! misho 36: static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz,
1.1.1.2 misho 37: struct in6_addr *client_addr, int is_unicast, time_t now);
1.1.1.5 ! misho 38: static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, int is_unicast, time_t now);
1.1 misho 39: static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
40: static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
1.1.1.2 misho 41: static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string);
1.1 misho 42: static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize);
43: static void *opt6_next(void *opts, void *end);
44: static unsigned int opt6_uint(unsigned char *opt, int offset, int size);
45: static void get_context_tag(struct state *state, struct dhcp_context *context);
46: static int check_ia(struct state *state, void *opt, void **endp, void **ia_option);
47: static int build_ia(struct state *state, int *t1cntr);
48: static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);
1.1.1.2 misho 49: static void mark_context_used(struct state *state, struct in6_addr *addr);
1.1 misho 50: static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
51: static int check_address(struct state *state, struct in6_addr *addr);
1.1.1.4 misho 52: static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state, time_t now);
53: static struct addrlist *config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
1.1.1.2 misho 54: static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
55: unsigned int *min_time, struct in6_addr *addr, time_t now);
1.1 misho 56: static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
57: static int add_local_addrs(struct dhcp_context *context);
1.1.1.2 misho 58: static struct dhcp_netid *add_options(struct state *state, int do_refresh);
1.1 misho 59: static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
1.1.1.2 misho 60: unsigned int *preferred_timep, unsigned int lease_time);
1.1 misho 61:
62: #define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
63: #define opt6_type(opt) (opt6_uint(opt, -4, 2))
64: #define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)]))
65:
1.1.1.2 misho 66: #define opt6_user_vendor_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2+(i)]))
67: #define opt6_user_vendor_len(opt) ((int)(opt6_uint(opt, -4, 2)))
68: #define opt6_user_vendor_next(opt, end) (opt6_next(((void *) opt) - 2, end))
69:
1.1 misho 70:
71: unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
1.1.1.2 misho 72: struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
73: size_t sz, struct in6_addr *client_addr, time_t now)
1.1 misho 74: {
75: struct dhcp_vendor *vendor;
76: int msg_type;
1.1.1.2 misho 77: struct state state;
1.1 misho 78:
79: if (sz <= 4)
80: return 0;
81:
82: msg_type = *((unsigned char *)daemon->dhcp_packet.iov_base);
83:
84: /* Mark these so we only match each at most once, to avoid tangled linked lists */
85: for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
86: vendor->netid.next = &vendor->netid;
87:
1.1.1.4 misho 88: reset_counter();
1.1.1.2 misho 89: state.context = context;
90: state.interface = interface;
91: state.iface_name = iface_name;
92: state.fallback = fallback;
93: state.ll_addr = ll_addr;
94: state.ula_addr = ula_addr;
95: state.mac_len = 0;
96: state.tags = NULL;
97: state.link_address = NULL;
98:
99: if (dhcp6_maybe_relay(&state, daemon->dhcp_packet.iov_base, sz, client_addr,
100: IN6_IS_ADDR_MULTICAST(client_addr), now))
1.1 misho 101: return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
102:
103: return 0;
104: }
105:
106: /* This cost me blood to write, it will probably cost you blood to understand - srk. */
1.1.1.5 ! misho 107: static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz,
1.1.1.2 misho 108: struct in6_addr *client_addr, int is_unicast, time_t now)
1.1 misho 109: {
110: void *end = inbuff + sz;
111: void *opts = inbuff + 34;
1.1.1.5 ! misho 112: int msg_type = *inbuff;
1.1 misho 113: unsigned char *outmsgtypep;
114: void *opt;
115: struct dhcp_vendor *vendor;
116:
1.1.1.4 misho 117: /* if not an encapsulated relayed message, just do the stuff */
1.1 misho 118: if (msg_type != DHCP6RELAYFORW)
119: {
120: /* if link_address != NULL if points to the link address field of the
121: innermost nested RELAYFORW message, which is where we find the
122: address of the network on which we can allocate an address.
1.1.1.2 misho 123: Recalculate the available contexts using that information.
124:
125: link_address == NULL means there's no relay in use, so we try and find the client's
126: MAC address from the local ND cache. */
1.1 misho 127:
1.1.1.2 misho 128: if (!state->link_address)
1.1.1.3 misho 129: get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type, now);
1.1.1.2 misho 130: else
1.1 misho 131: {
132: struct dhcp_context *c;
1.1.1.4 misho 133: struct shared_network *share = NULL;
1.1.1.2 misho 134: state->context = NULL;
1.1.1.4 misho 135:
1.1.1.2 misho 136: if (!IN6_IS_ADDR_LOOPBACK(state->link_address) &&
137: !IN6_IS_ADDR_LINKLOCAL(state->link_address) &&
138: !IN6_IS_ADDR_MULTICAST(state->link_address))
1.1 misho 139: for (c = daemon->dhcp6; c; c = c->next)
1.1.1.4 misho 140: {
141: for (share = daemon->shared_networks; share; share = share->next)
142: {
143: if (share->shared_addr.s_addr != 0)
144: continue;
145:
146: if (share->if_index != 0 ||
147: !IN6_ARE_ADDR_EQUAL(state->link_address, &share->match_addr6))
148: continue;
149:
150: if ((c->flags & CONTEXT_DHCP) &&
151: !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
152: is_same_net6(&share->shared_addr6, &c->start6, c->prefix) &&
153: is_same_net6(&share->shared_addr6, &c->end6, c->prefix))
154: break;
155: }
156:
157: if (share ||
158: ((c->flags & CONTEXT_DHCP) &&
159: !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
160: is_same_net6(state->link_address, &c->start6, c->prefix) &&
161: is_same_net6(state->link_address, &c->end6, c->prefix)))
162: {
163: c->preferred = c->valid = 0xffffffff;
164: c->current = state->context;
165: state->context = c;
166: }
167: }
1.1 misho 168:
1.1.1.2 misho 169: if (!state->context)
1.1 misho 170: {
1.1.1.2 misho 171: inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
1.1 misho 172: my_syslog(MS_DHCP | LOG_WARNING,
173: _("no address range available for DHCPv6 request from relay at %s"),
174: daemon->addrbuff);
175: return 0;
176: }
177: }
1.1.1.2 misho 178:
179: if (!state->context)
1.1 misho 180: {
181: my_syslog(MS_DHCP | LOG_WARNING,
1.1.1.2 misho 182: _("no address range available for DHCPv6 request via %s"), state->iface_name);
1.1 misho 183: return 0;
184: }
185:
1.1.1.2 misho 186: return dhcp6_no_relay(state, msg_type, inbuff, sz, is_unicast, now);
1.1 misho 187: }
188:
189: /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
190: which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
191: if (sz < 38)
192: return 0;
193:
194: /* copy header stuff into reply message and set type to reply */
1.1.1.2 misho 195: if (!(outmsgtypep = put_opt6(inbuff, 34)))
196: return 0;
1.1 misho 197: *outmsgtypep = DHCP6RELAYREPL;
198:
199: /* look for relay options and set tags if found. */
200: for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
201: {
202: int mopt;
203:
204: if (vendor->match_type == MATCH_SUBSCRIBER)
205: mopt = OPTION6_SUBSCRIBER_ID;
206: else if (vendor->match_type == MATCH_REMOTE)
207: mopt = OPTION6_REMOTE_ID;
208: else
209: continue;
210:
211: if ((opt = opt6_find(opts, end, mopt, 1)) &&
212: vendor->len == opt6_len(opt) &&
213: memcmp(vendor->data, opt6_ptr(opt, 0), vendor->len) == 0 &&
214: vendor->netid.next != &vendor->netid)
215: {
1.1.1.2 misho 216: vendor->netid.next = state->tags;
217: state->tags = &vendor->netid;
1.1 misho 218: break;
219: }
220: }
221:
1.1.1.2 misho 222: /* RFC-6939 */
223: if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3)))
224: {
1.1.1.4 misho 225: if (opt6_len(opt) - 2 > DHCP_CHADDR_MAX) {
226: return 0;
227: }
1.1.1.2 misho 228: state->mac_type = opt6_uint(opt, 0, 2);
229: state->mac_len = opt6_len(opt) - 2;
230: memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
231: }
232:
1.1 misho 233: for (opt = opts; opt; opt = opt6_next(opt, end))
234: {
1.1.1.4 misho 235: if (opt6_ptr(opt, 0) + opt6_len(opt) > end)
236: return 0;
237:
238: /* Don't copy MAC address into reply. */
239: if (opt6_type(opt) != OPTION6_CLIENT_MAC)
1.1 misho 240: {
1.1.1.4 misho 241: int o = new_opt6(opt6_type(opt));
242: if (opt6_type(opt) == OPTION6_RELAY_MSG)
243: {
244: struct in6_addr align;
245: /* the packet data is unaligned, copy to aligned storage */
246: memcpy(&align, inbuff + 2, IN6ADDRSZ);
247: state->link_address = &align;
248: /* zero is_unicast since that is now known to refer to the
249: relayed packet, not the original sent by the client */
250: if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
251: return 0;
252: }
253: else
254: put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
255: end_opt6(o);
256: }
1.1 misho 257: }
258:
259: return 1;
260: }
261:
1.1.1.5 ! misho 262: static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbuff, size_t sz, int is_unicast, time_t now)
1.1 misho 263: {
264: void *opt;
1.1.1.5 ! misho 265: int i, o, o1, start_opts, start_msg;
1.1 misho 266: struct dhcp_opt *opt_cfg;
267: struct dhcp_netid *tagif;
268: struct dhcp_config *config = NULL;
269: struct dhcp_netid known_id, iface_id, v6_id;
1.1.1.5 ! misho 270: unsigned char outmsgtype;
1.1 misho 271: struct dhcp_vendor *vendor;
272: struct dhcp_context *context_tmp;
1.1.1.2 misho 273: struct dhcp_mac *mac_opt;
1.1 misho 274: unsigned int ignore = 0;
275:
1.1.1.2 misho 276: state->packet_options = inbuff + 4;
277: state->end = inbuff + sz;
278: state->clid = NULL;
279: state->clid_len = 0;
280: state->lease_allocate = 0;
281: state->context_tags = NULL;
282: state->domain = NULL;
283: state->send_domain = NULL;
284: state->hostname_auth = 0;
285: state->hostname = NULL;
286: state->client_hostname = NULL;
1.1.1.4 misho 287: state->fqdn_flags = 0x01; /* default to send if we receive no FQDN option */
1.1 misho 288:
289: /* set tag with name == interface */
1.1.1.2 misho 290: iface_id.net = state->iface_name;
291: iface_id.next = state->tags;
292: state->tags = &iface_id;
1.1 misho 293:
294: /* set tag "dhcpv6" */
295: v6_id.net = "dhcpv6";
1.1.1.2 misho 296: v6_id.next = state->tags;
297: state->tags = &v6_id;
1.1 misho 298:
1.1.1.5 ! misho 299: start_msg = save_counter(-1);
! 300: /* copy over transaction-id */
! 301: if (!put_opt6(inbuff, 4))
1.1.1.2 misho 302: return 0;
1.1 misho 303: start_opts = save_counter(-1);
1.1.1.5 ! misho 304: state->xid = inbuff[3] | inbuff[2] << 8 | inbuff[1] << 16;
! 305:
1.1 misho 306: /* We're going to be linking tags from all context we use.
307: mark them as unused so we don't link one twice and break the list */
1.1.1.2 misho 308: for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
1.1 misho 309: {
1.1.1.2 misho 310: context_tmp->netid.next = &context_tmp->netid;
1.1 misho 311:
312: if (option_bool(OPT_LOG_OPTS))
313: {
314: inet_ntop(AF_INET6, &context_tmp->start6, daemon->dhcp_buff, ADDRSTRLEN);
315: inet_ntop(AF_INET6, &context_tmp->end6, daemon->dhcp_buff2, ADDRSTRLEN);
316: if (context_tmp->flags & (CONTEXT_STATIC))
317: my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCPv6 subnet: %s/%d"),
1.1.1.2 misho 318: state->xid, daemon->dhcp_buff, context_tmp->prefix);
1.1 misho 319: else
320: my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"),
1.1.1.2 misho 321: state->xid, daemon->dhcp_buff, daemon->dhcp_buff2);
1.1 misho 322: }
323: }
324:
1.1.1.2 misho 325: if ((opt = opt6_find(state->packet_options, state->end, OPTION6_CLIENT_ID, 1)))
1.1 misho 326: {
1.1.1.2 misho 327: state->clid = opt6_ptr(opt, 0);
328: state->clid_len = opt6_len(opt);
1.1 misho 329: o = new_opt6(OPTION6_CLIENT_ID);
1.1.1.2 misho 330: put_opt6(state->clid, state->clid_len);
1.1 misho 331: end_opt6(o);
332: }
333: else if (msg_type != DHCP6IREQ)
334: return 0;
335:
1.1.1.3 misho 336: /* server-id must match except for SOLICIT, CONFIRM and REBIND messages */
337: if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ && msg_type != DHCP6REBIND &&
1.1.1.2 misho 338: (!(opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1)) ||
1.1 misho 339: opt6_len(opt) != daemon->duid_len ||
340: memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
341: return 0;
342:
343: o = new_opt6(OPTION6_SERVER_ID);
344: put_opt6(daemon->duid, daemon->duid_len);
345: end_opt6(o);
346:
347: if (is_unicast &&
348: (msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
349:
350: {
1.1.1.5 ! misho 351: outmsgtype = DHCP6REPLY;
1.1 misho 352: o1 = new_opt6(OPTION6_STATUS_CODE);
353: put_opt6_short(DHCP6USEMULTI);
354: put_opt6_string("Use multicast");
355: end_opt6(o1);
1.1.1.5 ! misho 356: goto done;
1.1 misho 357: }
358:
359: /* match vendor and user class options */
360: for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
361: {
362: int mopt;
363:
364: if (vendor->match_type == MATCH_VENDOR)
365: mopt = OPTION6_VENDOR_CLASS;
366: else if (vendor->match_type == MATCH_USER)
367: mopt = OPTION6_USER_CLASS;
368: else
369: continue;
370:
1.1.1.2 misho 371: if ((opt = opt6_find(state->packet_options, state->end, mopt, 2)))
1.1 misho 372: {
373: void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt));
374: int offset = 0;
375:
376: if (mopt == OPTION6_VENDOR_CLASS)
377: {
378: if (opt6_len(opt) < 4)
379: continue;
380:
381: if (vendor->enterprise != opt6_uint(opt, 0, 4))
382: continue;
383:
384: offset = 4;
385: }
386:
1.1.1.2 misho 387: /* Note that format if user/vendor classes is different to DHCP options - no option types. */
388: for (enc_opt = opt6_ptr(opt, offset); enc_opt; enc_opt = opt6_user_vendor_next(enc_opt, enc_end))
389: for (i = 0; i <= (opt6_user_vendor_len(enc_opt) - vendor->len); i++)
390: if (memcmp(vendor->data, opt6_user_vendor_ptr(enc_opt, i), vendor->len) == 0)
1.1 misho 391: {
1.1.1.2 misho 392: vendor->netid.next = state->tags;
393: state->tags = &vendor->netid;
1.1 misho 394: break;
395: }
396: }
397: }
398:
1.1.1.2 misho 399: if (option_bool(OPT_LOG_OPTS) && (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
400: my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %u"), state->xid, opt6_uint(opt, 0, 4));
1.1 misho 401:
402: /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
403: Otherwise assume the option is an array, and look for a matching element.
1.1.1.4 misho 404: If no data given, existence of the option is enough. This code handles
1.1 misho 405: V-I opts too. */
406: for (opt_cfg = daemon->dhcp_match6; opt_cfg; opt_cfg = opt_cfg->next)
407: {
408: int match = 0;
409:
410: if (opt_cfg->flags & DHOPT_RFC3925)
411: {
1.1.1.2 misho 412: for (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_OPTS, 4);
1.1 misho 413: opt;
1.1.1.2 misho 414: opt = opt6_find(opt6_next(opt, state->end), state->end, OPTION6_VENDOR_OPTS, 4))
1.1 misho 415: {
416: void *vopt;
417: void *vend = opt6_ptr(opt, opt6_len(opt));
418:
419: for (vopt = opt6_find(opt6_ptr(opt, 4), vend, opt_cfg->opt, 0);
420: vopt;
421: vopt = opt6_find(opt6_next(vopt, vend), vend, opt_cfg->opt, 0))
422: if ((match = match_bytes(opt_cfg, opt6_ptr(vopt, 0), opt6_len(vopt))))
423: break;
424: }
425: if (match)
426: break;
427: }
428: else
429: {
1.1.1.2 misho 430: if (!(opt = opt6_find(state->packet_options, state->end, opt_cfg->opt, 1)))
1.1 misho 431: continue;
432:
433: match = match_bytes(opt_cfg, opt6_ptr(opt, 0), opt6_len(opt));
434: }
435:
436: if (match)
437: {
1.1.1.2 misho 438: opt_cfg->netid->next = state->tags;
439: state->tags = opt_cfg->netid;
1.1 misho 440: }
441: }
1.1.1.2 misho 442:
443: if (state->mac_len != 0)
444: {
445: if (option_bool(OPT_LOG_OPTS))
446: {
447: print_mac(daemon->dhcp_buff, state->mac, state->mac_len);
448: my_syslog(MS_DHCP | LOG_INFO, _("%u client MAC address: %s"), state->xid, daemon->dhcp_buff);
449: }
450:
451: for (mac_opt = daemon->dhcp_macs; mac_opt; mac_opt = mac_opt->next)
452: if ((unsigned)mac_opt->hwaddr_len == state->mac_len &&
453: ((unsigned)mac_opt->hwaddr_type == state->mac_type || mac_opt->hwaddr_type == 0) &&
454: memcmp_masked(mac_opt->hwaddr, state->mac, state->mac_len, mac_opt->mask))
455: {
456: mac_opt->netid.next = state->tags;
457: state->tags = &mac_opt->netid;
458: }
459: }
1.1 misho 460:
1.1.1.2 misho 461: if ((opt = opt6_find(state->packet_options, state->end, OPTION6_FQDN, 1)))
1.1 misho 462: {
463: /* RFC4704 refers */
464: int len = opt6_len(opt) - 1;
465:
1.1.1.2 misho 466: state->fqdn_flags = opt6_uint(opt, 0, 1);
1.1 misho 467:
468: /* Always force update, since the client has no way to do it itself. */
1.1.1.2 misho 469: if (!option_bool(OPT_FQDN_UPDATE) && !(state->fqdn_flags & 0x01))
470: state->fqdn_flags |= 0x03;
1.1 misho 471:
1.1.1.2 misho 472: state->fqdn_flags &= ~0x04;
1.1 misho 473:
474: if (len != 0 && len < 255)
475: {
476: unsigned char *pp, *op = opt6_ptr(opt, 1);
477: char *pq = daemon->dhcp_buff;
478:
479: pp = op;
480: while (*op != 0 && ((op + (*op)) - pp) < len)
481: {
482: memcpy(pq, op+1, *op);
483: pq += *op;
484: op += (*op)+1;
485: *(pq++) = '.';
486: }
487:
488: if (pq != daemon->dhcp_buff)
489: pq--;
490: *pq = 0;
491:
492: if (legal_hostname(daemon->dhcp_buff))
493: {
1.1.1.4 misho 494: struct dhcp_match_name *m;
495: size_t nl = strlen(daemon->dhcp_buff);
496:
1.1.1.2 misho 497: state->client_hostname = daemon->dhcp_buff;
1.1.1.4 misho 498:
1.1 misho 499: if (option_bool(OPT_LOG_OPTS))
1.1.1.4 misho 500: my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), state->xid, state->client_hostname);
501:
502: for (m = daemon->dhcp_name_match; m; m = m->next)
503: {
504: size_t ml = strlen(m->name);
505: char save = 0;
506:
507: if (nl < ml)
508: continue;
509: if (nl > ml)
510: {
511: save = state->client_hostname[ml];
512: state->client_hostname[ml] = 0;
513: }
514:
515: if (hostname_isequal(state->client_hostname, m->name) &&
516: (save == 0 || m->wildcard))
517: {
518: m->netid->next = state->tags;
519: state->tags = m->netid;
520: }
521:
522: if (save != 0)
523: state->client_hostname[ml] = save;
524: }
1.1 misho 525: }
526: }
527: }
528:
1.1.1.4 misho 529: if (state->clid &&
530: (config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len,
531: state->mac, state->mac_len, state->mac_type, NULL, run_tag_if(state->tags))) &&
532: have_config(config, CONFIG_NAME))
533: {
534: state->hostname = config->hostname;
535: state->domain = config->domain;
536: state->hostname_auth = 1;
537: }
538: else if (state->client_hostname)
1.1 misho 539: {
1.1.1.4 misho 540: state->domain = strip_hostname(state->client_hostname);
1.1 misho 541:
1.1.1.4 misho 542: if (strlen(state->client_hostname) != 0)
1.1 misho 543: {
1.1.1.4 misho 544: state->hostname = state->client_hostname;
1.1 misho 545:
1.1.1.4 misho 546: if (!config)
1.1 misho 547: {
1.1.1.4 misho 548: /* Search again now we have a hostname.
549: Only accept configs without CLID here, (it won't match)
550: to avoid impersonation by name. */
551: struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname, run_tag_if(state->tags));
552: if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
553: config = new;
1.1 misho 554: }
555: }
556: }
557:
558: if (config)
559: {
560: struct dhcp_netid_list *list;
561:
562: for (list = config->netid; list; list = list->next)
563: {
1.1.1.2 misho 564: list->list->next = state->tags;
565: state->tags = list->list;
1.1 misho 566: }
567:
568: /* set "known" tag for known hosts */
569: known_id.net = "known";
1.1.1.2 misho 570: known_id.next = state->tags;
571: state->tags = &known_id;
1.1 misho 572:
573: if (have_config(config, CONFIG_DISABLE))
574: ignore = 1;
575: }
1.1.1.4 misho 576: else if (state->clid &&
577: find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len,
578: state->mac, state->mac_len, state->mac_type, NULL, run_tag_if(state->tags)))
579: {
580: known_id.net = "known-othernet";
581: known_id.next = state->tags;
582: state->tags = &known_id;
583: }
584:
1.1.1.2 misho 585: tagif = run_tag_if(state->tags);
1.1 misho 586:
587: /* if all the netids in the ignore list are present, ignore this client */
588: if (daemon->dhcp_ignore)
589: {
590: struct dhcp_netid_list *id_list;
591:
592: for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
593: if (match_netid(id_list->list, tagif, 0))
594: ignore = 1;
595: }
596:
597: /* if all the netids in the ignore_name list are present, ignore client-supplied name */
1.1.1.2 misho 598: if (!state->hostname_auth)
1.1 misho 599: {
600: struct dhcp_netid_list *id_list;
601:
602: for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
603: if ((!id_list->list) || match_netid(id_list->list, tagif, 0))
604: break;
605: if (id_list)
1.1.1.2 misho 606: state->hostname = NULL;
1.1 misho 607: }
608:
609:
610: switch (msg_type)
611: {
612: default:
613: return 0;
1.1.1.2 misho 614:
615:
1.1 misho 616: case DHCP6SOLICIT:
617: {
618: int address_assigned = 0;
619: /* tags without all prefix-class tags */
1.1.1.2 misho 620: struct dhcp_netid *solicit_tags;
1.1 misho 621: struct dhcp_context *c;
1.1.1.2 misho 622:
1.1.1.5 ! misho 623: outmsgtype = DHCP6ADVERTISE;
1.1.1.2 misho 624:
625: if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0))
1.1 misho 626: {
1.1.1.5 ! misho 627: outmsgtype = DHCP6REPLY;
1.1.1.2 misho 628: state->lease_allocate = 1;
1.1 misho 629: o = new_opt6(OPTION6_RAPID_COMMIT);
630: end_opt6(o);
631: }
1.1.1.2 misho 632:
633: log6_quiet(state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL);
1.1 misho 634:
1.1.1.2 misho 635: request_no_address:
636: solicit_tags = tagif;
1.1 misho 637:
638: if (ignore)
639: return 0;
640:
641: /* reset USED bits in leases */
642: lease6_reset();
643:
644: /* Can use configured address max once per prefix */
1.1.1.2 misho 645: for (c = state->context; c; c = c->current)
1.1 misho 646: c->flags &= ~CONTEXT_CONF_USED;
647:
1.1.1.2 misho 648: for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
1.1 misho 649: {
650: void *ia_option, *ia_end;
651: unsigned int min_time = 0xffffffff;
652: int t1cntr;
653: int ia_counter;
654: /* set unless we're sending a particular prefix-class, when we
655: want only dhcp-ranges with the correct tags set and not those without any tags. */
656: int plain_range = 1;
1.1.1.2 misho 657: u32 lease_time;
1.1 misho 658: struct dhcp_lease *ltmp;
1.1.1.4 misho 659: struct in6_addr req_addr, addr;
660:
1.1.1.2 misho 661: if (!check_ia(state, opt, &ia_end, &ia_option))
1.1 misho 662: continue;
663:
664: /* reset USED bits in contexts - one address per prefix per IAID */
1.1.1.2 misho 665: for (c = state->context; c; c = c->current)
1.1 misho 666: c->flags &= ~CONTEXT_USED;
667:
1.1.1.2 misho 668: o = build_ia(state, &t1cntr);
1.1.1.3 misho 669: if (address_assigned)
670: address_assigned = 2;
1.1 misho 671:
672: for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
673: {
1.1.1.4 misho 674: /* worry about alignment here. */
675: memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
1.1.1.2 misho 676:
1.1.1.4 misho 677: if ((c = address6_valid(state->context, &req_addr, solicit_tags, plain_range)))
1.1 misho 678: {
679: lease_time = c->lease_time;
680: /* If the client asks for an address on the same network as a configured address,
681: offer the configured address instead, to make moving to newly-configured
682: addresses automatic. */
1.1.1.4 misho 683: if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr, state, now))
1.1 misho 684: {
1.1.1.4 misho 685: req_addr = addr;
1.1 misho 686: mark_config_used(c, &addr);
687: if (have_config(config, CONFIG_TIME))
688: lease_time = config->lease_time;
689: }
1.1.1.4 misho 690: else if (!(c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
1.1 misho 691: continue; /* not an address we're allowed */
1.1.1.4 misho 692: else if (!check_address(state, &req_addr))
1.1 misho 693: continue; /* address leased elsewhere */
694:
695: /* add address to output packet */
1.1.1.4 misho 696: add_address(state, c, lease_time, ia_option, &min_time, &req_addr, now);
697: mark_context_used(state, &req_addr);
1.1.1.2 misho 698: get_context_tag(state, c);
1.1 misho 699: address_assigned = 1;
700: }
701: }
702:
703: /* Suggest configured address(es) */
1.1.1.2 misho 704: for (c = state->context; c; c = c->current)
1.1 misho 705: if (!(c->flags & CONTEXT_CONF_USED) &&
706: match_netid(c->filter, solicit_tags, plain_range) &&
1.1.1.4 misho 707: config_valid(config, c, &addr, state, now))
1.1 misho 708: {
1.1.1.2 misho 709: mark_config_used(state->context, &addr);
1.1 misho 710: if (have_config(config, CONFIG_TIME))
711: lease_time = config->lease_time;
712: else
713: lease_time = c->lease_time;
1.1.1.4 misho 714:
1.1 misho 715: /* add address to output packet */
1.1.1.2 misho 716: add_address(state, c, lease_time, NULL, &min_time, &addr, now);
717: mark_context_used(state, &addr);
718: get_context_tag(state, c);
1.1 misho 719: address_assigned = 1;
720: }
721:
722: /* return addresses for existing leases */
723: ltmp = NULL;
1.1.1.2 misho 724: while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid)))
1.1 misho 725: {
1.1.1.4 misho 726: req_addr = ltmp->addr6;
727: if ((c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
1.1 misho 728: {
1.1.1.4 misho 729: add_address(state, c, c->lease_time, NULL, &min_time, &req_addr, now);
730: mark_context_used(state, &req_addr);
1.1.1.2 misho 731: get_context_tag(state, c);
1.1 misho 732: address_assigned = 1;
733: }
734: }
735:
736: /* Return addresses for all valid contexts which don't yet have one */
1.1.1.2 misho 737: while ((c = address6_allocate(state->context, state->clid, state->clid_len, state->ia_type == OPTION6_IA_TA,
738: state->iaid, ia_counter, solicit_tags, plain_range, &addr)))
1.1 misho 739: {
1.1.1.2 misho 740: add_address(state, c, c->lease_time, NULL, &min_time, &addr, now);
741: mark_context_used(state, &addr);
742: get_context_tag(state, c);
1.1 misho 743: address_assigned = 1;
744: }
745:
1.1.1.3 misho 746: if (address_assigned != 1)
747: {
748: /* If the server will not assign any addresses to any IAs in a
749: subsequent Request from the client, the server MUST send an Advertise
750: message to the client that doesn't include any IA options. */
751: if (!state->lease_allocate)
752: {
753: save_counter(o);
754: continue;
755: }
756:
757: /* If the server cannot assign any addresses to an IA in the message
758: from the client, the server MUST include the IA in the Reply message
759: with no addresses in the IA and a Status Code option in the IA
760: containing status code NoAddrsAvail. */
761: o1 = new_opt6(OPTION6_STATUS_CODE);
762: put_opt6_short(DHCP6NOADDRS);
763: put_opt6_string(_("address unavailable"));
764: end_opt6(o1);
765: }
766:
1.1 misho 767: end_ia(t1cntr, min_time, 0);
768: end_opt6(o);
769: }
770:
771: if (address_assigned)
772: {
773: o1 = new_opt6(OPTION6_STATUS_CODE);
774: put_opt6_short(DHCP6SUCCESS);
775: put_opt6_string(_("success"));
776: end_opt6(o1);
777:
778: /* If --dhcp-authoritative is set, we can tell client not to wait for
779: other possible servers */
780: o = new_opt6(OPTION6_PREFERENCE);
781: put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0);
782: end_opt6(o);
1.1.1.2 misho 783: tagif = add_options(state, 0);
1.1 misho 784: }
785: else
786: {
787: /* no address, return error */
788: o1 = new_opt6(OPTION6_STATUS_CODE);
789: put_opt6_short(DHCP6NOADDRS);
790: put_opt6_string(_("no addresses available"));
791: end_opt6(o1);
1.1.1.3 misho 792:
793: /* Some clients will ask repeatedly when we're not giving
794: out addresses because we're in stateless mode. Avoid spamming
795: the log in that case. */
796: for (c = state->context; c; c = c->current)
797: if (!(c->flags & CONTEXT_RA_STATELESS))
798: {
799: log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
800: break;
801: }
1.1 misho 802: }
803:
804: break;
805: }
806:
807: case DHCP6REQUEST:
808: {
809: int address_assigned = 0;
1.1.1.2 misho 810: int start = save_counter(-1);
811:
1.1 misho 812: /* set reply message type */
1.1.1.5 ! misho 813: outmsgtype = DHCP6REPLY;
1.1.1.2 misho 814: state->lease_allocate = 1;
1.1 misho 815:
1.1.1.2 misho 816: log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
1.1 misho 817:
818: if (ignore)
819: return 0;
820:
1.1.1.2 misho 821: for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
1.1 misho 822: {
823: void *ia_option, *ia_end;
824: unsigned int min_time = 0xffffffff;
825: int t1cntr;
826:
1.1.1.2 misho 827: if (!check_ia(state, opt, &ia_end, &ia_option))
1.1 misho 828: continue;
1.1.1.2 misho 829:
830: if (!ia_option)
831: {
1.1.1.4 misho 832: /* If we get a request with an IA_*A without addresses, treat it exactly like
1.1.1.2 misho 833: a SOLICT with rapid commit set. */
834: save_counter(start);
835: goto request_no_address;
836: }
837:
838: o = build_ia(state, &t1cntr);
1.1 misho 839:
840: for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
841: {
1.1.1.4 misho 842: struct in6_addr req_addr;
1.1 misho 843: struct dhcp_context *dynamic, *c;
844: unsigned int lease_time;
845: int config_ok = 0;
1.1.1.4 misho 846:
847: /* align. */
848: memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
1.1 misho 849:
1.1.1.4 misho 850: if ((c = address6_valid(state->context, &req_addr, tagif, 1)))
851: config_ok = (config_implies(config, c, &req_addr) != NULL);
1.1 misho 852:
1.1.1.4 misho 853: if ((dynamic = address6_available(state->context, &req_addr, tagif, 1)) || c)
1.1 misho 854: {
855: if (!dynamic && !config_ok)
856: {
857: /* Static range, not configured. */
858: o1 = new_opt6(OPTION6_STATUS_CODE);
1.1.1.3 misho 859: put_opt6_short(DHCP6NOADDRS);
1.1 misho 860: put_opt6_string(_("address unavailable"));
861: end_opt6(o1);
862: }
1.1.1.4 misho 863: else if (!check_address(state, &req_addr))
1.1 misho 864: {
865: /* Address leased to another DUID/IAID */
866: o1 = new_opt6(OPTION6_STATUS_CODE);
867: put_opt6_short(DHCP6UNSPEC);
868: put_opt6_string(_("address in use"));
869: end_opt6(o1);
870: }
871: else
872: {
873: if (!dynamic)
874: dynamic = c;
875:
876: lease_time = dynamic->lease_time;
877:
878: if (config_ok && have_config(config, CONFIG_TIME))
879: lease_time = config->lease_time;
880:
1.1.1.4 misho 881: add_address(state, dynamic, lease_time, ia_option, &min_time, &req_addr, now);
1.1.1.2 misho 882: get_context_tag(state, dynamic);
1.1 misho 883: address_assigned = 1;
884: }
885: }
886: else
887: {
888: /* requested address not on the correct link */
889: o1 = new_opt6(OPTION6_STATUS_CODE);
890: put_opt6_short(DHCP6NOTONLINK);
891: put_opt6_string(_("not on link"));
892: end_opt6(o1);
893: }
894: }
895:
896: end_ia(t1cntr, min_time, 0);
897: end_opt6(o);
898: }
899:
900: if (address_assigned)
901: {
902: o1 = new_opt6(OPTION6_STATUS_CODE);
903: put_opt6_short(DHCP6SUCCESS);
904: put_opt6_string(_("success"));
905: end_opt6(o1);
906: }
907: else
908: {
909: /* no address, return error */
910: o1 = new_opt6(OPTION6_STATUS_CODE);
911: put_opt6_short(DHCP6NOADDRS);
912: put_opt6_string(_("no addresses available"));
913: end_opt6(o1);
1.1.1.2 misho 914: log6_packet(state, "DHCPREPLY", NULL, _("no addresses available"));
1.1 misho 915: }
916:
1.1.1.2 misho 917: tagif = add_options(state, 0);
1.1 misho 918: break;
919: }
920:
921:
922: case DHCP6RENEW:
1.1.1.5 ! misho 923: case DHCP6REBIND:
1.1 misho 924: {
1.1.1.5 ! misho 925: int address_assigned = 0;
! 926:
1.1 misho 927: /* set reply message type */
1.1.1.5 ! misho 928: outmsgtype = DHCP6REPLY;
1.1 misho 929:
1.1.1.5 ! misho 930: log6_quiet(state, msg_type == DHCP6RENEW ? "DHCPRENEW" : "DHCPREBIND", NULL, NULL);
1.1 misho 931:
1.1.1.2 misho 932: for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
1.1 misho 933: {
934: void *ia_option, *ia_end;
935: unsigned int min_time = 0xffffffff;
936: int t1cntr, iacntr;
937:
1.1.1.2 misho 938: if (!check_ia(state, opt, &ia_end, &ia_option))
1.1 misho 939: continue;
940:
1.1.1.2 misho 941: o = build_ia(state, &t1cntr);
1.1 misho 942: iacntr = save_counter(-1);
943:
944: for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
945: {
946: struct dhcp_lease *lease = NULL;
1.1.1.4 misho 947: struct in6_addr req_addr;
1.1.1.2 misho 948: unsigned int preferred_time = opt6_uint(ia_option, 16, 4);
949: unsigned int valid_time = opt6_uint(ia_option, 20, 4);
1.1 misho 950: char *message = NULL;
951: struct dhcp_context *this_context;
1.1.1.4 misho 952:
953: memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
1.1 misho 954:
1.1.1.2 misho 955: if (!(lease = lease6_find(state->clid, state->clid_len,
956: state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
1.1.1.4 misho 957: state->iaid, &req_addr)))
1.1 misho 958: {
1.1.1.5 ! misho 959: if (msg_type == DHCP6REBIND)
! 960: {
! 961: /* When rebinding, we can create a lease if it doesn't exist. */
! 962: lease = lease6_allocate(&req_addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
! 963: if (lease)
! 964: lease_set_iaid(lease, state->iaid);
! 965: else
! 966: break;
! 967: }
! 968: else
! 969: {
! 970: /* If the server cannot find a client entry for the IA the server
! 971: returns the IA containing no addresses with a Status Code option set
! 972: to NoBinding in the Reply message. */
! 973: save_counter(iacntr);
! 974: t1cntr = 0;
! 975:
! 976: log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
! 977:
! 978: o1 = new_opt6(OPTION6_STATUS_CODE);
! 979: put_opt6_short(DHCP6NOBINDING);
! 980: put_opt6_string(_("no binding found"));
! 981: end_opt6(o1);
! 982:
! 983: preferred_time = valid_time = 0;
! 984: break;
! 985: }
1.1 misho 986: }
987:
1.1.1.4 misho 988: if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
989: (this_context = address6_valid(state->context, &req_addr, tagif, 1)))
1.1 misho 990: {
991: unsigned int lease_time;
992:
1.1.1.2 misho 993: get_context_tag(state, this_context);
1.1 misho 994:
1.1.1.4 misho 995: if (config_implies(config, this_context, &req_addr) && have_config(config, CONFIG_TIME))
1.1 misho 996: lease_time = config->lease_time;
997: else
998: lease_time = this_context->lease_time;
999:
1.1.1.2 misho 1000: calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time);
1.1 misho 1001:
1002: lease_set_expires(lease, valid_time, now);
1.1.1.2 misho 1003: /* Update MAC record in case it's new information. */
1004: if (state->mac_len != 0)
1005: lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
1006: if (state->ia_type == OPTION6_IA_NA && state->hostname)
1.1 misho 1007: {
1.1.1.4 misho 1008: char *addr_domain = get_domain6(&req_addr);
1.1.1.2 misho 1009: if (!state->send_domain)
1010: state->send_domain = addr_domain;
1011: lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
1012: message = state->hostname;
1.1 misho 1013: }
1014:
1015:
1016: if (preferred_time == 0)
1017: message = _("deprecated");
1.1.1.5 ! misho 1018:
! 1019: address_assigned = 1;
1.1 misho 1020: }
1021: else
1.1.1.2 misho 1022: {
1023: preferred_time = valid_time = 0;
1024: message = _("address invalid");
1.1.1.3 misho 1025: }
1.1.1.2 misho 1026:
1.1.1.3 misho 1027: if (message && (message != state->hostname))
1.1.1.4 misho 1028: log6_packet(state, "DHCPREPLY", &req_addr, message);
1.1.1.2 misho 1029: else
1.1.1.4 misho 1030: log6_quiet(state, "DHCPREPLY", &req_addr, message);
1.1.1.2 misho 1031:
1.1 misho 1032: o1 = new_opt6(OPTION6_IAADDR);
1.1.1.4 misho 1033: put_opt6(&req_addr, sizeof(req_addr));
1.1 misho 1034: put_opt6_long(preferred_time);
1035: put_opt6_long(valid_time);
1036: end_opt6(o1);
1037: }
1038:
1039: end_ia(t1cntr, min_time, 1);
1040: end_opt6(o);
1041: }
1.1.1.5 ! misho 1042:
! 1043: if (!address_assigned && msg_type == DHCP6REBIND)
! 1044: {
! 1045: /* can't create lease for any address, return error */
! 1046: o1 = new_opt6(OPTION6_STATUS_CODE);
! 1047: put_opt6_short(DHCP6NOADDRS);
! 1048: put_opt6_string(_("no addresses available"));
! 1049: end_opt6(o1);
! 1050: }
1.1 misho 1051:
1.1.1.2 misho 1052: tagif = add_options(state, 0);
1.1 misho 1053: break;
1054: }
1055:
1056: case DHCP6CONFIRM:
1057: {
1.1.1.3 misho 1058: int good_addr = 0;
1059:
1.1 misho 1060: /* set reply message type */
1.1.1.5 ! misho 1061: outmsgtype = DHCP6REPLY;
1.1 misho 1062:
1.1.1.2 misho 1063: log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
1.1 misho 1064:
1.1.1.2 misho 1065: for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
1.1 misho 1066: {
1067: void *ia_option, *ia_end;
1068:
1.1.1.2 misho 1069: for (check_ia(state, opt, &ia_end, &ia_option);
1.1 misho 1070: ia_option;
1071: ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
1072: {
1.1.1.4 misho 1073: struct in6_addr req_addr;
1074:
1075: /* alignment */
1076: memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
1.1 misho 1077:
1.1.1.4 misho 1078: if (!address6_valid(state->context, &req_addr, tagif, 1))
1.1 misho 1079: {
1080: o1 = new_opt6(OPTION6_STATUS_CODE);
1081: put_opt6_short(DHCP6NOTONLINK);
1082: put_opt6_string(_("confirm failed"));
1083: end_opt6(o1);
1.1.1.4 misho 1084: log6_quiet(state, "DHCPREPLY", &req_addr, _("confirm failed"));
1.1 misho 1085: return 1;
1086: }
1087:
1.1.1.3 misho 1088: good_addr = 1;
1.1.1.4 misho 1089: log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname);
1.1 misho 1090: }
1091: }
1.1.1.3 misho 1092:
1093: /* No addresses, no reply: RFC 3315 18.2.2 */
1094: if (!good_addr)
1095: return 0;
1.1 misho 1096:
1097: o1 = new_opt6(OPTION6_STATUS_CODE);
1098: put_opt6_short(DHCP6SUCCESS );
1099: put_opt6_string(_("all addresses still on link"));
1100: end_opt6(o1);
1101: break;
1102: }
1103:
1104: case DHCP6IREQ:
1105: {
1106: /* We can't discriminate contexts based on address, as we don't know it.
1107: If there is only one possible context, we can use its tags */
1.1.1.2 misho 1108: if (state->context && state->context->netid.net && !state->context->current)
1.1 misho 1109: {
1.1.1.2 misho 1110: state->context->netid.next = NULL;
1111: state->context_tags = &state->context->netid;
1.1 misho 1112: }
1.1.1.2 misho 1113:
1114: /* Similarly, we can't determine domain from address, but if the FQDN is
1115: given in --dhcp-host, we can use that, and failing that we can use the
1116: unqualified configured domain, if any. */
1117: if (state->hostname_auth)
1118: state->send_domain = state->domain;
1119: else
1120: state->send_domain = get_domain6(NULL);
1121:
1122: log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname);
1.1 misho 1123: if (ignore)
1124: return 0;
1.1.1.5 ! misho 1125: outmsgtype = DHCP6REPLY;
1.1.1.2 misho 1126: tagif = add_options(state, 1);
1.1 misho 1127: break;
1128: }
1129:
1130:
1131: case DHCP6RELEASE:
1132: {
1133: /* set reply message type */
1.1.1.5 ! misho 1134: outmsgtype = DHCP6REPLY;
1.1 misho 1135:
1.1.1.2 misho 1136: log6_quiet(state, "DHCPRELEASE", NULL, NULL);
1.1 misho 1137:
1.1.1.2 misho 1138: for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
1.1 misho 1139: {
1140: void *ia_option, *ia_end;
1141: int made_ia = 0;
1142:
1.1.1.2 misho 1143: for (check_ia(state, opt, &ia_end, &ia_option);
1.1 misho 1144: ia_option;
1145: ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
1146: {
1147: struct dhcp_lease *lease;
1.1.1.4 misho 1148: struct in6_addr addr;
1149:
1150: /* align */
1151: memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
1.1.1.2 misho 1152: if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
1.1.1.4 misho 1153: state->iaid, &addr)))
1.1 misho 1154: lease_prune(lease, now);
1155: else
1156: {
1157: if (!made_ia)
1158: {
1.1.1.2 misho 1159: o = new_opt6(state->ia_type);
1160: put_opt6_long(state->iaid);
1161: if (state->ia_type == OPTION6_IA_NA)
1.1 misho 1162: {
1163: put_opt6_long(0);
1164: put_opt6_long(0);
1165: }
1166: made_ia = 1;
1167: }
1168:
1169: o1 = new_opt6(OPTION6_IAADDR);
1.1.1.4 misho 1170: put_opt6(&addr, IN6ADDRSZ);
1.1 misho 1171: put_opt6_long(0);
1172: put_opt6_long(0);
1173: end_opt6(o1);
1174: }
1175: }
1176:
1177: if (made_ia)
1178: {
1179: o1 = new_opt6(OPTION6_STATUS_CODE);
1180: put_opt6_short(DHCP6NOBINDING);
1181: put_opt6_string(_("no binding found"));
1182: end_opt6(o1);
1183:
1184: end_opt6(o);
1185: }
1186: }
1187:
1188: o1 = new_opt6(OPTION6_STATUS_CODE);
1189: put_opt6_short(DHCP6SUCCESS);
1190: put_opt6_string(_("release received"));
1191: end_opt6(o1);
1192:
1193: break;
1194: }
1195:
1196: case DHCP6DECLINE:
1197: {
1198: /* set reply message type */
1.1.1.5 ! misho 1199: outmsgtype = DHCP6REPLY;
1.1 misho 1200:
1.1.1.2 misho 1201: log6_quiet(state, "DHCPDECLINE", NULL, NULL);
1.1 misho 1202:
1.1.1.2 misho 1203: for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
1.1 misho 1204: {
1205: void *ia_option, *ia_end;
1206: int made_ia = 0;
1207:
1.1.1.2 misho 1208: for (check_ia(state, opt, &ia_end, &ia_option);
1.1 misho 1209: ia_option;
1210: ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
1211: {
1212: struct dhcp_lease *lease;
1.1.1.4 misho 1213: struct in6_addr addr;
1214: struct addrlist *addr_list;
1215:
1216: /* align */
1217: memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
1.1 misho 1218:
1.1.1.4 misho 1219: if ((addr_list = config_implies(config, state->context, &addr)))
1.1 misho 1220: {
1221: prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
1.1.1.4 misho 1222: inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
1.1 misho 1223: my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
1224: daemon->addrbuff, daemon->dhcp_buff3);
1.1.1.4 misho 1225: addr_list->flags |= ADDRLIST_DECLINED;
1226: addr_list->decline_time = now;
1.1 misho 1227: }
1228: else
1229: /* make sure this host gets a different address next time. */
1.1.1.2 misho 1230: for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
1231: context_tmp->addr_epoch++;
1.1 misho 1232:
1.1.1.2 misho 1233: if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
1.1.1.4 misho 1234: state->iaid, &addr)))
1.1 misho 1235: lease_prune(lease, now);
1236: else
1237: {
1238: if (!made_ia)
1239: {
1.1.1.2 misho 1240: o = new_opt6(state->ia_type);
1241: put_opt6_long(state->iaid);
1242: if (state->ia_type == OPTION6_IA_NA)
1.1 misho 1243: {
1244: put_opt6_long(0);
1245: put_opt6_long(0);
1246: }
1247: made_ia = 1;
1248: }
1249:
1250: o1 = new_opt6(OPTION6_IAADDR);
1.1.1.4 misho 1251: put_opt6(&addr, IN6ADDRSZ);
1.1 misho 1252: put_opt6_long(0);
1253: put_opt6_long(0);
1254: end_opt6(o1);
1255: }
1256: }
1257:
1258: if (made_ia)
1259: {
1260: o1 = new_opt6(OPTION6_STATUS_CODE);
1261: put_opt6_short(DHCP6NOBINDING);
1262: put_opt6_string(_("no binding found"));
1263: end_opt6(o1);
1264:
1265: end_opt6(o);
1266: }
1267:
1268: }
1.1.1.3 misho 1269:
1.1.1.4 misho 1270: /* We must answer with 'success' in global section anyway */
1.1.1.3 misho 1271: o1 = new_opt6(OPTION6_STATUS_CODE);
1272: put_opt6_short(DHCP6SUCCESS);
1273: put_opt6_string(_("success"));
1274: end_opt6(o1);
1.1 misho 1275: break;
1276: }
1277:
1278: }
1.1.1.5 ! misho 1279:
1.1.1.2 misho 1280: log_tags(tagif, state->xid);
1.1.1.5 ! misho 1281:
! 1282: done:
! 1283: /* Fill in the message type. Note that we store the offset,
! 1284: not a direct pointer, since the packet memory may have been
! 1285: reallocated. */
! 1286: ((unsigned char *)(daemon->outpacket.iov_base))[start_msg] = outmsgtype;
! 1287:
1.1.1.2 misho 1288: log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
1.1 misho 1289:
1290: return 1;
1291:
1292: }
1293:
1.1.1.2 misho 1294: static struct dhcp_netid *add_options(struct state *state, int do_refresh)
1.1 misho 1295: {
1296: void *oro;
1297: /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
1298: struct dhcp_netid *tagif = option_filter(state->tags, state->context_tags, daemon->dhcp_opts6);
1299: struct dhcp_opt *opt_cfg;
1.1.1.2 misho 1300: int done_dns = 0, done_refresh = !do_refresh, do_encap = 0;
1.1 misho 1301: int i, o, o1;
1302:
1303: oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0);
1304:
1305: for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1306: {
1307: /* netids match and not encapsulated? */
1308: if (!(opt_cfg->flags & DHOPT_TAGOK))
1309: continue;
1310:
1311: if (!(opt_cfg->flags & DHOPT_FORCE) && oro)
1312: {
1313: for (i = 0; i < opt6_len(oro) - 1; i += 2)
1314: if (opt6_uint(oro, i, 2) == (unsigned)opt_cfg->opt)
1315: break;
1316:
1317: /* option not requested */
1318: if (i >= opt6_len(oro) - 1)
1319: continue;
1320: }
1321:
1.1.1.2 misho 1322: if (opt_cfg->opt == OPTION6_REFRESH_TIME)
1323: done_refresh = 1;
1.1.1.3 misho 1324:
1325: if (opt_cfg->opt == OPTION6_DNS_SERVER)
1326: done_dns = 1;
1.1 misho 1327:
1328: if (opt_cfg->flags & DHOPT_ADDR6)
1329: {
1.1.1.2 misho 1330: int len, j;
1331: struct in6_addr *a;
1332:
1333: for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0;
1334: j < opt_cfg->len; j += IN6ADDRSZ, a++)
1335: if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
1336: (IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)))
1337: len -= IN6ADDRSZ;
1338:
1339: if (len != 0)
1340: {
1341:
1342: o = new_opt6(opt_cfg->opt);
1343:
1344: for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
1345: {
1.1.1.4 misho 1346: struct in6_addr *p = NULL;
1347:
1.1.1.2 misho 1348: if (IN6_IS_ADDR_UNSPECIFIED(a))
1349: {
1350: if (!add_local_addrs(state->context))
1.1.1.4 misho 1351: p = state->fallback;
1.1.1.2 misho 1352: }
1353: else if (IN6_IS_ADDR_ULA_ZERO(a))
1354: {
1355: if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))
1.1.1.4 misho 1356: p = state->ula_addr;
1.1.1.2 misho 1357: }
1358: else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
1359: {
1360: if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
1.1.1.4 misho 1361: p = state->ll_addr;
1.1.1.2 misho 1362: }
1363: else
1.1.1.4 misho 1364: p = a;
1365:
1366: if (!p)
1367: continue;
1368: else if (opt_cfg->opt == OPTION6_NTP_SERVER)
1369: {
1370: if (IN6_IS_ADDR_MULTICAST(p))
1371: o1 = new_opt6(NTP_SUBOPTION_MC_ADDR);
1372: else
1373: o1 = new_opt6(NTP_SUBOPTION_SRV_ADDR);
1374: put_opt6(p, IN6ADDRSZ);
1375: end_opt6(o1);
1376: }
1377: else
1378: put_opt6(p, IN6ADDRSZ);
1.1 misho 1379: }
1.1.1.2 misho 1380:
1381: end_opt6(o);
1382: }
1383: }
1384: else
1385: {
1386: o = new_opt6(opt_cfg->opt);
1387: if (opt_cfg->val)
1388: put_opt6(opt_cfg->val, opt_cfg->len);
1389: end_opt6(o);
1.1 misho 1390: }
1391: }
1392:
1.1.1.2 misho 1393: if (daemon->port == NAMESERVER_PORT && !done_dns)
1.1 misho 1394: {
1395: o = new_opt6(OPTION6_DNS_SERVER);
1.1.1.2 misho 1396: if (!add_local_addrs(state->context))
1397: put_opt6(state->fallback, IN6ADDRSZ);
1398: end_opt6(o);
1399: }
1400:
1401: if (state->context && !done_refresh)
1402: {
1403: struct dhcp_context *c;
1404: unsigned int lease_time = 0xffffffff;
1405:
1406: /* Find the smallest lease tie of all contexts,
1.1.1.4 misho 1407: subject to the RFC-4242 stipulation that this must not
1.1.1.2 misho 1408: be less than 600. */
1409: for (c = state->context; c; c = c->next)
1410: if (c->lease_time < lease_time)
1411: {
1412: if (c->lease_time < 600)
1413: lease_time = 600;
1414: else
1415: lease_time = c->lease_time;
1416: }
1417:
1418: o = new_opt6(OPTION6_REFRESH_TIME);
1419: put_opt6_long(lease_time);
1.1 misho 1420: end_opt6(o);
1421: }
1422:
1423: /* handle vendor-identifying vendor-encapsulated options,
1424: dhcp-option = vi-encap:13,17,....... */
1425: for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1426: opt_cfg->flags &= ~DHOPT_ENCAP_DONE;
1427:
1428: if (oro)
1429: for (i = 0; i < opt6_len(oro) - 1; i += 2)
1430: if (opt6_uint(oro, i, 2) == OPTION6_VENDOR_OPTS)
1431: do_encap = 1;
1432:
1433: for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1434: {
1435: if (opt_cfg->flags & DHOPT_RFC3925)
1436: {
1437: int found = 0;
1438: struct dhcp_opt *oc;
1439:
1440: if (opt_cfg->flags & DHOPT_ENCAP_DONE)
1441: continue;
1442:
1443: for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1444: {
1445: oc->flags &= ~DHOPT_ENCAP_MATCH;
1446:
1447: if (!(oc->flags & DHOPT_RFC3925) || opt_cfg->u.encap != oc->u.encap)
1448: continue;
1449:
1450: oc->flags |= DHOPT_ENCAP_DONE;
1451: if (match_netid(oc->netid, tagif, 1))
1452: {
1453: /* option requested/forced? */
1454: if (!oro || do_encap || (oc->flags & DHOPT_FORCE))
1455: {
1456: oc->flags |= DHOPT_ENCAP_MATCH;
1457: found = 1;
1458: }
1459: }
1460: }
1461:
1462: if (found)
1463: {
1464: o = new_opt6(OPTION6_VENDOR_OPTS);
1465: put_opt6_long(opt_cfg->u.encap);
1466:
1467: for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1468: if (oc->flags & DHOPT_ENCAP_MATCH)
1469: {
1470: o1 = new_opt6(oc->opt);
1471: put_opt6(oc->val, oc->len);
1472: end_opt6(o1);
1473: }
1474: end_opt6(o);
1475: }
1476: }
1477: }
1478:
1479:
1480: if (state->hostname)
1481: {
1482: unsigned char *p;
1483: size_t len = strlen(state->hostname);
1484:
1485: if (state->send_domain)
1.1.1.2 misho 1486: len += strlen(state->send_domain) + 2;
1.1 misho 1487:
1488: o = new_opt6(OPTION6_FQDN);
1.1.1.2 misho 1489: if ((p = expand(len + 2)))
1.1 misho 1490: {
1491: *(p++) = state->fqdn_flags;
1.1.1.4 misho 1492: p = do_rfc1035_name(p, state->hostname, NULL);
1.1 misho 1493: if (state->send_domain)
1.1.1.2 misho 1494: {
1.1.1.4 misho 1495: p = do_rfc1035_name(p, state->send_domain, NULL);
1.1.1.2 misho 1496: *p = 0;
1497: }
1.1 misho 1498: }
1499: end_opt6(o);
1500: }
1501:
1502:
1503: /* logging */
1504: if (option_bool(OPT_LOG_OPTS) && oro)
1505: {
1506: char *q = daemon->namebuff;
1507: for (i = 0; i < opt6_len(oro) - 1; i += 2)
1508: {
1509: char *s = option_string(AF_INET6, opt6_uint(oro, i, 2), NULL, 0, NULL, 0);
1510: q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
1511: "%d%s%s%s",
1512: opt6_uint(oro, i, 2),
1513: strlen(s) != 0 ? ":" : "",
1514: s,
1515: (i > opt6_len(oro) - 3) ? "" : ", ");
1516: if ( i > opt6_len(oro) - 3 || (q - daemon->namebuff) > 40)
1517: {
1518: q = daemon->namebuff;
1519: my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), state->xid, daemon->namebuff);
1520: }
1521: }
1522: }
1523:
1524: return tagif;
1525: }
1526:
1527: static int add_local_addrs(struct dhcp_context *context)
1528: {
1529: int done = 0;
1530:
1531: for (; context; context = context->current)
1532: if ((context->flags & CONTEXT_USED) && !IN6_IS_ADDR_UNSPECIFIED(&context->local6))
1533: {
1534: /* squash duplicates */
1535: struct dhcp_context *c;
1536: for (c = context->current; c; c = c->current)
1537: if ((c->flags & CONTEXT_USED) &&
1538: IN6_ARE_ADDR_EQUAL(&context->local6, &c->local6))
1539: break;
1540:
1541: if (!c)
1542: {
1543: done = 1;
1544: put_opt6(&context->local6, IN6ADDRSZ);
1545: }
1546: }
1547:
1548: return done;
1549: }
1550:
1551:
1552: static void get_context_tag(struct state *state, struct dhcp_context *context)
1553: {
1554: /* get tags from context if we've not used it before */
1555: if (context->netid.next == &context->netid && context->netid.net)
1556: {
1557: context->netid.next = state->context_tags;
1558: state->context_tags = &context->netid;
1559: if (!state->hostname_auth)
1560: {
1561: struct dhcp_netid_list *id_list;
1562:
1563: for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1564: if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1565: break;
1566: if (id_list)
1567: state->hostname = NULL;
1568: }
1569: }
1570: }
1571:
1572: static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
1573: {
1574: state->ia_type = opt6_type(opt);
1575: *ia_option = NULL;
1576:
1577: if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
1578: return 0;
1579:
1580: if (state->ia_type == OPTION6_IA_NA && opt6_len(opt) < 12)
1581: return 0;
1582:
1583: if (state->ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
1584: return 0;
1585:
1586: *endp = opt6_ptr(opt, opt6_len(opt));
1587: state->iaid = opt6_uint(opt, 0, 4);
1588: *ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
1589:
1590: return 1;
1591: }
1592:
1593:
1594: static int build_ia(struct state *state, int *t1cntr)
1595: {
1596: int o = new_opt6(state->ia_type);
1597:
1598: put_opt6_long(state->iaid);
1599: *t1cntr = 0;
1600:
1601: if (state->ia_type == OPTION6_IA_NA)
1602: {
1603: /* save pointer */
1604: *t1cntr = save_counter(-1);
1605: /* so we can fill these in later */
1606: put_opt6_long(0);
1607: put_opt6_long(0);
1608: }
1609:
1610: return o;
1611: }
1612:
1613: static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
1614: {
1615: if (t1cntr != 0)
1616: {
1.1.1.4 misho 1617: /* go back and fill in fields in IA_NA option */
1.1 misho 1618: int sav = save_counter(t1cntr);
1619: unsigned int t1, t2, fuzz = 0;
1620:
1621: if (do_fuzz)
1622: {
1623: fuzz = rand16();
1624:
1625: while (fuzz > (min_time/16))
1626: fuzz = fuzz/2;
1627: }
1628:
1629: t1 = (min_time == 0xffffffff) ? 0xffffffff : min_time/2 - fuzz;
1630: t2 = (min_time == 0xffffffff) ? 0xffffffff : ((min_time/8)*7) - fuzz;
1631: put_opt6_long(t1);
1632: put_opt6_long(t2);
1633: save_counter(sav);
1634: }
1635: }
1636:
1.1.1.2 misho 1637: static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
1638: unsigned int *min_time, struct in6_addr *addr, time_t now)
1.1 misho 1639: {
1.1.1.2 misho 1640: unsigned int valid_time = 0, preferred_time = 0;
1.1 misho 1641: int o = new_opt6(OPTION6_IAADDR);
1642: struct dhcp_lease *lease;
1643:
1.1.1.2 misho 1644: /* get client requested times */
1645: if (ia_option)
1646: {
1647: preferred_time = opt6_uint(ia_option, 16, 4);
1648: valid_time = opt6_uint(ia_option, 20, 4);
1649: }
1650:
1651: calculate_times(context, min_time, &valid_time, &preferred_time, lease_time);
1.1 misho 1652:
1653: put_opt6(addr, sizeof(*addr));
1654: put_opt6_long(preferred_time);
1655: put_opt6_long(valid_time);
1656: end_opt6(o);
1657:
1.1.1.2 misho 1658: if (state->lease_allocate)
1.1 misho 1659: update_leases(state, context, addr, valid_time, now);
1660:
1661: if ((lease = lease6_find_by_addr(addr, 128, 0)))
1662: lease->flags |= LEASE_USED;
1663:
1664: /* get tags from context if we've not used it before */
1665: if (context->netid.next == &context->netid && context->netid.net)
1666: {
1667: context->netid.next = state->context_tags;
1668: state->context_tags = &context->netid;
1669:
1670: if (!state->hostname_auth)
1671: {
1672: struct dhcp_netid_list *id_list;
1673:
1674: for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1675: if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1676: break;
1677: if (id_list)
1678: state->hostname = NULL;
1679: }
1680: }
1681:
1.1.1.2 misho 1682: log6_quiet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
1.1 misho 1683:
1684: }
1685:
1.1.1.2 misho 1686: static void mark_context_used(struct state *state, struct in6_addr *addr)
1.1 misho 1687: {
1.1.1.2 misho 1688: struct dhcp_context *context;
1689:
1.1 misho 1690: /* Mark that we have an address for this prefix. */
1.1.1.2 misho 1691: for (context = state->context; context; context = context->current)
1.1 misho 1692: if (is_same_net6(addr, &context->start6, context->prefix))
1693: context->flags |= CONTEXT_USED;
1694: }
1695:
1696: static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)
1697: {
1698: for (; context; context = context->current)
1699: if (is_same_net6(addr, &context->start6, context->prefix))
1700: context->flags |= CONTEXT_CONF_USED;
1701: }
1702:
1703: /* make sure address not leased to another CLID/IAID */
1704: static int check_address(struct state *state, struct in6_addr *addr)
1705: {
1706: struct dhcp_lease *lease;
1707:
1708: if (!(lease = lease6_find_by_addr(addr, 128, 0)))
1709: return 1;
1710:
1711: if (lease->clid_len != state->clid_len ||
1712: memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
1.1.1.2 misho 1713: lease->iaid != state->iaid)
1.1 misho 1714: return 0;
1715:
1716: return 1;
1717: }
1718:
1.1.1.2 misho 1719:
1.1.1.4 misho 1720: /* return true of *addr could have been generated from config. */
1721: static struct addrlist *config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
1722: {
1723: int prefix;
1724: struct in6_addr wild_addr;
1725: struct addrlist *addr_list;
1726:
1727: if (!config || !(config->flags & CONFIG_ADDR6))
1728: return NULL;
1729:
1730: for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
1731: {
1732: prefix = (addr_list->flags & ADDRLIST_PREFIX) ? addr_list->prefixlen : 128;
1733: wild_addr = addr_list->addr.addr6;
1734:
1735: if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
1736: {
1737: wild_addr = context->start6;
1738: setaddr6part(&wild_addr, addr6part(&addr_list->addr.addr6));
1739: }
1740: else if (!is_same_net6(&context->start6, addr, context->prefix))
1741: continue;
1742:
1743: if (is_same_net6(&wild_addr, addr, prefix))
1744: return addr_list;
1745: }
1746:
1747: return NULL;
1748: }
1749:
1750: static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state, time_t now)
1751: {
1752: u64 addrpart, i, addresses;
1753: struct addrlist *addr_list;
1754:
1755: if (!config || !(config->flags & CONFIG_ADDR6))
1756: return 0;
1757:
1758: for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
1759: if (!(addr_list->flags & ADDRLIST_DECLINED) ||
1760: difftime(now, addr_list->decline_time) >= (float)DECLINE_BACKOFF)
1761: {
1762: addrpart = addr6part(&addr_list->addr.addr6);
1763: addresses = 1;
1764:
1765: if (addr_list->flags & ADDRLIST_PREFIX)
1766: addresses = (u64)1<<(128-addr_list->prefixlen);
1767:
1768: if ((addr_list->flags & ADDRLIST_WILDCARD))
1769: {
1770: if (context->prefix != 64)
1771: continue;
1772:
1773: *addr = context->start6;
1774: }
1775: else if (is_same_net6(&context->start6, &addr_list->addr.addr6, context->prefix))
1776: *addr = addr_list->addr.addr6;
1777: else
1778: continue;
1779:
1780: for (i = 0 ; i < addresses; i++)
1781: {
1782: setaddr6part(addr, addrpart+i);
1783:
1784: if (check_address(state, addr))
1785: return 1;
1786: }
1787: }
1788:
1789: return 0;
1790: }
1791:
1.1.1.2 misho 1792: /* Calculate valid and preferred times to send in leases/renewals.
1793:
1794: Inputs are:
1795:
1796: *valid_timep, *preferred_timep - requested times from IAADDR options.
1797: context->valid, context->preferred - times associated with subnet address on local interface.
1798: context->flags | CONTEXT_DEPRECATE - "deprecated" flag in dhcp-range.
1799: lease_time - configured time for context for individual client.
1800: *min_time - smallest valid time sent so far.
1801:
1802: Outputs are :
1803:
1804: *valid_timep, *preferred_timep - times to be send in IAADDR option.
1805: *min_time - smallest valid time sent so far, to calculate T1 and T2.
1806:
1807: */
1.1 misho 1808: static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
1.1.1.2 misho 1809: unsigned int *preferred_timep, unsigned int lease_time)
1.1 misho 1810: {
1.1.1.2 misho 1811: unsigned int req_preferred = *preferred_timep, req_valid = *valid_timep;
1812: unsigned int valid_time = lease_time, preferred_time = lease_time;
1813:
1814: /* RFC 3315: "A server ignores the lifetimes set
1815: by the client if the preferred lifetime is greater than the valid
1816: lifetime. */
1817: if (req_preferred <= req_valid)
1818: {
1819: if (req_preferred != 0)
1820: {
1821: /* 0 == "no preference from client" */
1822: if (req_preferred < 120u)
1823: req_preferred = 120u; /* sanity */
1824:
1825: if (req_preferred < preferred_time)
1826: preferred_time = req_preferred;
1827: }
1828:
1829: if (req_valid != 0)
1830: /* 0 == "no preference from client" */
1831: {
1832: if (req_valid < 120u)
1833: req_valid = 120u; /* sanity */
1834:
1835: if (req_valid < valid_time)
1836: valid_time = req_valid;
1837: }
1838: }
1.1 misho 1839:
1.1.1.2 misho 1840: /* deprecate (preferred == 0) which configured, or when local address
1841: is deprecated */
1842: if ((context->flags & CONTEXT_DEPRECATE) || context->preferred == 0)
1.1 misho 1843: preferred_time = 0;
1.1.1.2 misho 1844:
1.1 misho 1845: if (preferred_time != 0 && preferred_time < *min_time)
1846: *min_time = preferred_time;
1847:
1848: if (valid_time != 0 && valid_time < *min_time)
1849: *min_time = valid_time;
1850:
1851: *valid_timep = valid_time;
1852: *preferred_timep = preferred_time;
1853: }
1854:
1855: static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now)
1856: {
1857: struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0);
1.1.1.2 misho 1858: #ifdef HAVE_SCRIPT
1.1 misho 1859: struct dhcp_netid *tagif = run_tag_if(state->tags);
1.1.1.2 misho 1860: #endif
1861:
1862: (void)context;
1.1 misho 1863:
1864: if (!lease)
1865: lease = lease6_allocate(addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
1866:
1867: if (lease)
1868: {
1869: lease_set_expires(lease, lease_time, now);
1.1.1.2 misho 1870: lease_set_iaid(lease, state->iaid);
1871: lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
1.1 misho 1872: lease_set_interface(lease, state->interface, now);
1873: if (state->hostname && state->ia_type == OPTION6_IA_NA)
1874: {
1875: char *addr_domain = get_domain6(addr);
1876: if (!state->send_domain)
1877: state->send_domain = addr_domain;
1878: lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
1879: }
1880:
1881: #ifdef HAVE_SCRIPT
1882: if (daemon->lease_change_command)
1883: {
1.1.1.5 ! misho 1884: void *opt;
! 1885:
1.1 misho 1886: lease->flags |= LEASE_CHANGED;
1887: free(lease->extradata);
1888: lease->extradata = NULL;
1889: lease->extradata_size = lease->extradata_len = 0;
1890: lease->vendorclass_count = 0;
1891:
1.1.1.5 ! misho 1892: if ((opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
1.1 misho 1893: {
1.1.1.5 ! misho 1894: void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt));
1.1 misho 1895: lease->vendorclass_count++;
1896: /* send enterprise number first */
1.1.1.5 ! misho 1897: sprintf(daemon->dhcp_buff2, "%u", opt6_uint(opt, 0, 4));
1.1 misho 1898: lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
1899:
1.1.1.5 ! misho 1900: if (opt6_len(opt) >= 6)
! 1901: for (enc_opt = opt6_ptr(opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1.1 misho 1902: {
1903: lease->vendorclass_count++;
1904: lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1905: }
1906: }
1907:
1908: lease_add_extradata(lease, (unsigned char *)state->client_hostname,
1909: state->client_hostname ? strlen(state->client_hostname) : 0, 0);
1910:
1.1.1.5 ! misho 1911: /* DNSMASQ_REQUESTED_OPTIONS */
! 1912: if ((opt = opt6_find(state->packet_options, state->end, OPTION6_ORO, 2)))
! 1913: {
! 1914: int i, len = opt6_len(opt)/2;
! 1915: u16 *rop = opt6_ptr(opt, 0);
! 1916:
! 1917: for (i = 0; i < len; i++)
! 1918: lease_add_extradata(lease, (unsigned char *)daemon->namebuff,
! 1919: sprintf(daemon->namebuff, "%u", ntohs(rop[i])), (i + 1) == len ? 0 : ',');
! 1920: }
! 1921: else
! 1922: lease_add_extradata(lease, NULL, 0, 0);
! 1923:
! 1924: if ((opt = opt6_find(state->packet_options, state->end, OPTION6_MUD_URL, 1)))
! 1925: lease_add_extradata(lease, opt6_ptr(opt, 0), opt6_len(opt), 0);
! 1926: else
! 1927: lease_add_extradata(lease, NULL, 0, 0);
! 1928:
1.1 misho 1929: /* space-concat tag set */
1930: if (!tagif && !context->netid.net)
1931: lease_add_extradata(lease, NULL, 0, 0);
1932: else
1933: {
1934: if (context->netid.net)
1935: lease_add_extradata(lease, (unsigned char *)context->netid.net, strlen(context->netid.net), tagif ? ' ' : 0);
1936:
1937: if (tagif)
1938: {
1939: struct dhcp_netid *n;
1940: for (n = tagif; n; n = n->next)
1941: {
1942: struct dhcp_netid *n1;
1943: /* kill dupes */
1944: for (n1 = n->next; n1; n1 = n1->next)
1945: if (strcmp(n->net, n1->net) == 0)
1946: break;
1947: if (!n1)
1948: lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
1949: }
1950: }
1951: }
1952:
1953: if (state->link_address)
1954: inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
1955:
1956: lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);
1957:
1.1.1.5 ! misho 1958: if ((opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
1.1 misho 1959: {
1.1.1.5 ! misho 1960: void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt));
! 1961: for (enc_opt = opt6_ptr(opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1.1 misho 1962: lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1963: }
1964: }
1965: #endif
1966:
1967: }
1968: }
1969:
1970:
1971:
1972: static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts)
1973: {
1974: void *opt;
1975: char *desc = nest ? "nest" : "sent";
1976:
1.1.1.2 misho 1977: if (!option_bool(OPT_LOG_OPTS) || start_opts == end_opts)
1.1 misho 1978: return;
1979:
1980: for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
1981: {
1982: int type = opt6_type(opt);
1983: void *ia_options = NULL;
1984: char *optname;
1985:
1986: if (type == OPTION6_IA_NA)
1987: {
1988: sprintf(daemon->namebuff, "IAID=%u T1=%u T2=%u",
1989: opt6_uint(opt, 0, 4), opt6_uint(opt, 4, 4), opt6_uint(opt, 8, 4));
1990: optname = "ia-na";
1991: ia_options = opt6_ptr(opt, 12);
1992: }
1993: else if (type == OPTION6_IA_TA)
1994: {
1995: sprintf(daemon->namebuff, "IAID=%u", opt6_uint(opt, 0, 4));
1996: optname = "ia-ta";
1997: ia_options = opt6_ptr(opt, 4);
1998: }
1999: else if (type == OPTION6_IAADDR)
2000: {
1.1.1.4 misho 2001: struct in6_addr addr;
2002:
2003: /* align */
2004: memcpy(&addr, opt6_ptr(opt, 0), IN6ADDRSZ);
2005: inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
1.1 misho 2006: sprintf(daemon->namebuff, "%s PL=%u VL=%u",
2007: daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
2008: optname = "iaaddr";
2009: ia_options = opt6_ptr(opt, 24);
2010: }
2011: else if (type == OPTION6_STATUS_CODE)
2012: {
2013: int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
2014: memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
2015: daemon->namebuff[len + opt6_len(opt) - 2] = 0;
2016: optname = "status";
2017: }
2018: else
2019: {
2020: /* account for flag byte on FQDN */
2021: int offset = type == OPTION6_FQDN ? 1 : 0;
2022: optname = option_string(AF_INET6, type, opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
2023: }
2024:
2025: my_syslog(MS_DHCP | LOG_INFO, "%u %s size:%3d option:%3d %s %s",
2026: xid, desc, opt6_len(opt), type, optname, daemon->namebuff);
2027:
2028: if (ia_options)
2029: log6_opts(1, xid, ia_options, opt6_ptr(opt, opt6_len(opt)));
2030: }
2031: }
2032:
1.1.1.2 misho 2033: static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string)
2034: {
2035: if (option_bool(OPT_LOG_OPTS) || !option_bool(OPT_QUIET_DHCP6))
2036: log6_packet(state, type, addr, string);
2037: }
2038:
1.1 misho 2039: static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string)
2040: {
2041: int clid_len = state->clid_len;
2042:
2043: /* avoid buffer overflow */
2044: if (clid_len > 100)
2045: clid_len = 100;
2046:
2047: print_mac(daemon->namebuff, state->clid, clid_len);
2048:
2049: if (addr)
2050: {
1.1.1.4 misho 2051: inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, DHCP_BUFF_SZ - 1);
1.1 misho 2052: strcat(daemon->dhcp_buff2, " ");
2053: }
2054: else
2055: daemon->dhcp_buff2[0] = 0;
2056:
2057: if(option_bool(OPT_LOG_OPTS))
2058: my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s %s",
2059: state->xid,
2060: type,
2061: state->iface_name,
2062: daemon->dhcp_buff2,
2063: daemon->namebuff,
2064: string ? string : "");
2065: else
2066: my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s %s",
2067: type,
2068: state->iface_name,
2069: daemon->dhcp_buff2,
2070: daemon->namebuff,
2071: string ? string : "");
2072: }
2073:
2074: static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
2075: {
2076: u16 opt, opt_len;
2077: void *start;
2078:
2079: if (!opts)
2080: return NULL;
2081:
2082: while (1)
2083: {
2084: if (end - opts < 4)
2085: return NULL;
2086:
2087: start = opts;
2088: GETSHORT(opt, opts);
2089: GETSHORT(opt_len, opts);
2090:
2091: if (opt_len > (end - opts))
2092: return NULL;
2093:
2094: if (opt == search && (opt_len >= minsize))
2095: return start;
2096:
2097: opts += opt_len;
2098: }
2099: }
2100:
2101: static void *opt6_next(void *opts, void *end)
2102: {
2103: u16 opt_len;
2104:
2105: if (end - opts < 4)
2106: return NULL;
2107:
2108: opts += 2;
2109: GETSHORT(opt_len, opts);
2110:
2111: if (opt_len >= (end - opts))
2112: return NULL;
2113:
2114: return opts + opt_len;
2115: }
2116:
2117: static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
2118: {
2119: /* this worries about unaligned data and byte order */
2120: unsigned int ret = 0;
2121: int i;
2122: unsigned char *p = opt6_ptr(opt, offset);
2123:
2124: for (i = 0; i < size; i++)
2125: ret = (ret << 8) | *p++;
2126:
2127: return ret;
2128: }
2129:
1.1.1.5 ! misho 2130: int relay_upstream6(int iface_index, ssize_t sz,
! 2131: struct in6_addr *peer_address, u32 scope_id, time_t now)
1.1.1.2 misho 2132: {
2133: unsigned char *header;
2134: unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2135: int msg_type = *inbuff;
1.1.1.5 ! misho 2136: int hopcount, o;
1.1.1.2 misho 2137: struct in6_addr multicast;
2138: unsigned int maclen, mactype;
2139: unsigned char mac[DHCP_CHADDR_MAX];
1.1.1.5 ! misho 2140: struct dhcp_relay *relay;
! 2141:
! 2142: for (relay = daemon->relay6; relay; relay = relay->next)
! 2143: if (relay->iface_index != 0 && relay->iface_index == iface_index)
! 2144: break;
1.1.1.2 misho 2145:
1.1.1.5 ! misho 2146: /* No relay config. */
! 2147: if (!relay)
! 2148: return 0;
! 2149:
1.1.1.2 misho 2150: inet_pton(AF_INET6, ALL_SERVERS, &multicast);
1.1.1.3 misho 2151: get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
1.1.1.5 ! misho 2152:
1.1.1.2 misho 2153: /* Get hop count from nested relayed message */
2154: if (msg_type == DHCP6RELAYFORW)
2155: hopcount = *((unsigned char *)inbuff+1) + 1;
2156: else
2157: hopcount = 0;
2158:
1.1.1.4 misho 2159: reset_counter();
1.1.1.2 misho 2160:
1.1.1.5 ! misho 2161: /* RFC 3315 HOP_COUNT_LIMIT */
! 2162: if (hopcount > 32 || !(header = put_opt6(NULL, 34)))
! 2163: return 1;
! 2164:
! 2165: header[0] = DHCP6RELAYFORW;
! 2166: header[1] = hopcount;
! 2167: memcpy(&header[18], peer_address, IN6ADDRSZ);
! 2168:
! 2169: /* RFC-6939 */
! 2170: if (maclen != 0)
1.1.1.2 misho 2171: {
1.1.1.5 ! misho 2172: o = new_opt6(OPTION6_CLIENT_MAC);
! 2173: put_opt6_short(mactype);
! 2174: put_opt6(mac, maclen);
1.1.1.2 misho 2175: end_opt6(o);
1.1.1.5 ! misho 2176: }
! 2177:
! 2178: o = new_opt6(OPTION6_RELAY_MSG);
! 2179: put_opt6(inbuff, sz);
! 2180: end_opt6(o);
! 2181:
! 2182: for (; relay; relay = relay->next)
! 2183: if (relay->iface_index != 0 && relay->iface_index == iface_index)
! 2184: {
! 2185: union mysockaddr to;
1.1.1.2 misho 2186:
1.1.1.5 ! misho 2187: memcpy(&header[2], &relay->local.addr6, IN6ADDRSZ);
! 2188:
! 2189: to.sa.sa_family = AF_INET6;
! 2190: to.in6.sin6_addr = relay->server.addr6;
! 2191: to.in6.sin6_port = htons(relay->port);
! 2192: to.in6.sin6_flowinfo = 0;
! 2193: to.in6.sin6_scope_id = 0;
! 2194:
! 2195: if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
! 2196: {
! 2197: int multicast_iface;
! 2198: if (!relay->interface || strchr(relay->interface, '*') ||
! 2199: (multicast_iface = if_nametoindex(relay->interface)) == 0 ||
! 2200: setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
! 2201: {
! 2202: my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast DHCP relay via interface %s"), relay->interface);
! 2203: continue;
! 2204: }
! 2205: }
! 2206:
! 2207: #ifdef HAVE_DUMPFILE
! 2208: dump_packet_udp(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), NULL, &to, daemon->dhcp6fd);
! 2209: #endif
1.1.1.2 misho 2210:
1.1.1.5 ! misho 2211: while (retry_send(sendto(daemon->dhcp6fd, (void *)daemon->outpacket.iov_base, save_counter(-1),
! 2212: 0, (struct sockaddr *)&to, sa_len(&to))));
! 2213:
! 2214: if (option_bool(OPT_LOG_OPTS))
! 2215: {
! 2216: inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
! 2217: if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
! 2218: snprintf(daemon->namebuff, MAXDNAME, _("multicast via %s"), relay->interface);
! 2219: else
! 2220: inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
! 2221: my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay at %s -> %s"), daemon->addrbuff, daemon->namebuff);
! 2222: }
! 2223:
! 2224: }
! 2225:
! 2226: return 1;
1.1.1.2 misho 2227: }
2228:
1.1.1.5 ! misho 2229: int relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
1.1.1.2 misho 2230: {
2231: struct dhcp_relay *relay;
2232: struct in6_addr link;
2233: unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2234:
2235: /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
2236: which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
2237:
2238: if (sz < 38 || *inbuff != DHCP6RELAYREPL)
2239: return 0;
2240:
2241: memcpy(&link, &inbuff[2], IN6ADDRSZ);
2242:
2243: for (relay = daemon->relay6; relay; relay = relay->next)
1.1.1.4 misho 2244: if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr6) &&
1.1.1.2 misho 2245: (!relay->interface || wildcard_match(relay->interface, arrival_interface)))
2246: break;
2247:
1.1.1.4 misho 2248: reset_counter();
1.1.1.2 misho 2249:
2250: if (relay)
2251: {
2252: void *opt, *opts = inbuff + 34;
2253: void *end = inbuff + sz;
2254: for (opt = opts; opt; opt = opt6_next(opt, end))
2255: if (opt6_type(opt) == OPTION6_RELAY_MSG && opt6_len(opt) > 0)
2256: {
2257: int encap_type = *((unsigned char *)opt6_ptr(opt, 0));
2258: put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
2259: memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
2260: peer->sin6_scope_id = relay->iface_index;
1.1.1.5 ! misho 2261:
! 2262: if (encap_type == DHCP6RELAYREPL)
! 2263: {
! 2264: peer->sin6_port = ntohs(DHCPV6_SERVER_PORT);
! 2265: return 1;
! 2266: }
! 2267:
! 2268: peer->sin6_port = ntohs(DHCPV6_CLIENT_PORT);
! 2269:
! 2270: #ifdef HAVE_SCRIPT
! 2271: if (daemon->lease_change_command && encap_type == DHCP6REPLY)
! 2272: {
! 2273: /* decapsulate relayed message */
! 2274: opts = opt6_ptr(opt, 4);
! 2275: end = opt6_ptr(opt, opt6_len(opt));
! 2276:
! 2277: for (opt = opts; opt; opt = opt6_next(opt, end))
! 2278: if (opt6_type(opt) == OPTION6_IA_PD && opt6_len(opt) > 12)
! 2279: {
! 2280: void *ia_opts = opt6_ptr(opt, 12);
! 2281: void *ia_end = opt6_ptr(opt, opt6_len(opt));
! 2282: void *ia_opt;
! 2283:
! 2284: for (ia_opt = ia_opts; ia_opt; ia_opt = opt6_next(ia_opt, ia_end))
! 2285: /* valid lifetime must not be zero. */
! 2286: if (opt6_type(ia_opt) == OPTION6_IAPREFIX && opt6_len(ia_opt) >= 25 && opt6_uint(ia_opt, 4, 4) != 0)
! 2287: {
! 2288: if (daemon->free_snoops ||
! 2289: (daemon->free_snoops = whine_malloc(sizeof(struct snoop_record))))
! 2290: {
! 2291: struct snoop_record *snoop = daemon->free_snoops;
! 2292:
! 2293: daemon->free_snoops = snoop->next;
! 2294: snoop->client = peer->sin6_addr;
! 2295: snoop->prefix_len = opt6_uint(ia_opt, 8, 1);
! 2296: memcpy(&snoop->prefix, opt6_ptr(ia_opt, 9), IN6ADDRSZ);
! 2297: snoop->next = relay->snoop_records;
! 2298: relay->snoop_records = snoop;
! 2299: }
! 2300: }
! 2301: }
! 2302: }
! 2303: #endif
! 2304: return 1;
1.1.1.2 misho 2305: }
1.1.1.5 ! misho 2306:
1.1.1.2 misho 2307: }
1.1.1.5 ! misho 2308:
! 2309: return 0;
! 2310: }
1.1.1.2 misho 2311:
1.1.1.5 ! misho 2312: #ifdef HAVE_SCRIPT
! 2313: int do_snoop_script_run(void)
! 2314: {
! 2315: struct dhcp_relay *relay;
! 2316: struct snoop_record *snoop;
! 2317:
! 2318: for (relay = daemon->relay6; relay; relay = relay->next)
! 2319: if ((snoop = relay->snoop_records))
! 2320: {
! 2321: relay->snoop_records = snoop->next;
! 2322: snoop->next = daemon->free_snoops;
! 2323: daemon->free_snoops = snoop;
! 2324:
! 2325: queue_relay_snoop(&snoop->client, relay->iface_index, &snoop->prefix, snoop->prefix_len);
! 2326: return 1;
! 2327: }
! 2328:
1.1.1.2 misho 2329: return 0;
2330: }
1.1.1.5 ! misho 2331: #endif
1.1.1.2 misho 2332:
1.1 misho 2333: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>