blob: 223944bf9c1d3c191ae44e342aac9c0bddfc0b3a [file] [log] [blame]
Simon Kelleyd1ced3a2018-01-01 22:18:03 +00001/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
Simon Kelleyc72daea2012-01-05 21:33:27 +00002
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
Simon Kelleya6ebfac2013-03-06 20:52:35 +000022struct state {
23 unsigned char *clid;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +010024 int clid_len, iaid, ia_type, interface, hostname_auth, lease_allocate;
Simon Kelleya6ebfac2013-03-06 20:52:35 +000025 char *client_hostname, *hostname, *domain, *send_domain;
26 struct dhcp_context *context;
Simon Kelleyc3a04082014-01-11 22:18:19 +000027 struct in6_addr *link_address, *fallback, *ll_addr, *ula_addr;
Simon Kelleya6ebfac2013-03-06 20:52:35 +000028 unsigned int xid, fqdn_flags;
29 char *iface_name;
30 void *packet_options, *end;
31 struct dhcp_netid *tags, *context_tags;
Simon Kelley8939c952013-09-25 11:49:34 +010032 unsigned char mac[DHCP_CHADDR_MAX];
Simon Kelley89500e32013-09-20 16:29:20 +010033 unsigned int mac_len, mac_type;
Simon Kelleyc6309242013-03-07 20:59:28 +000034#ifdef OPTION6_PREFIX_CLASS
35 struct prefix_class *send_prefix_class;
36#endif
Simon Kelleya6ebfac2013-03-06 20:52:35 +000037};
38
Simon Kelley8939c952013-09-25 11:49:34 +010039static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
40 struct in6_addr *client_addr, int is_unicast, time_t now);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010041static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now);
Simon Kelley6c8f21e2012-03-12 15:06:55 +000042static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
Simon Kelleya6ebfac2013-03-06 20:52:35 +000043static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +010044static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string);
Simon Kelley4cb1b322012-02-06 14:30:41 +000045static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize);
46static void *opt6_next(void *opts, void *end);
47static unsigned int opt6_uint(unsigned char *opt, int offset, int size);
Simon Kelleya6ebfac2013-03-06 20:52:35 +000048static void get_context_tag(struct state *state, struct dhcp_context *context);
Simon Kelley3a654c52013-03-06 22:17:48 +000049static int check_ia(struct state *state, void *opt, void **endp, void **ia_option);
Simon Kelleya6ebfac2013-03-06 20:52:35 +000050static int build_ia(struct state *state, int *t1cntr);
51static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);
Simon Kelleyc6309242013-03-07 20:59:28 +000052#ifdef OPTION6_PREFIX_CLASS
53static struct prefix_class *prefix_class_from_context(struct dhcp_context *context);
54#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010055static void mark_context_used(struct state *state, struct in6_addr *addr);
Simon Kelleyde92b472013-03-15 18:25:10 +000056static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
57static int check_address(struct state *state, struct in6_addr *addr);
Simon Kelleycc4baaa2013-08-05 15:03:44 +010058static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
Simon Kelleyc8f2dd82013-09-13 11:22:55 +010059 unsigned int *min_time, struct in6_addr *addr, time_t now);
Simon Kelleya6ebfac2013-03-06 20:52:35 +000060static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
61static int add_local_addrs(struct dhcp_context *context);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010062static struct dhcp_netid *add_options(struct state *state, int do_refresh);
Simon Kelleyde92b472013-03-15 18:25:10 +000063static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
Simon Kelleycc4baaa2013-08-05 15:03:44 +010064 unsigned int *preferred_timep, unsigned int lease_time);
Simon Kelley62779782012-02-10 21:19:25 +000065
Simon Kelley4cb1b322012-02-06 14:30:41 +000066#define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
67#define opt6_type(opt) (opt6_uint(opt, -4, 2))
68#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)]))
69
Tanguy Bouzelocef1d7422013-10-03 11:06:31 +010070#define opt6_user_vendor_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2+(i)]))
71#define opt6_user_vendor_len(opt) ((int)(opt6_uint(opt, -4, 2)))
72#define opt6_user_vendor_next(opt, end) (opt6_next(((void *) opt) - 2, end))
73
Simon Kelley4cb1b322012-02-06 14:30:41 +000074
Simon Kelley1d0f91c2012-03-12 11:56:22 +000075unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
Simon Kelleyc3a04082014-01-11 22:18:19 +000076 struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
77 size_t sz, struct in6_addr *client_addr, time_t now)
Simon Kelleyc72daea2012-01-05 21:33:27 +000078{
Simon Kelley4cb1b322012-02-06 14:30:41 +000079 struct dhcp_vendor *vendor;
Simon Kelley1d0f91c2012-03-12 11:56:22 +000080 int msg_type;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010081 struct state state;
Simon Kelley1d0f91c2012-03-12 11:56:22 +000082
83 if (sz <= 4)
84 return 0;
85
86 msg_type = *((unsigned char *)daemon->dhcp_packet.iov_base);
87
Simon Kelley4cb1b322012-02-06 14:30:41 +000088 /* Mark these so we only match each at most once, to avoid tangled linked lists */
89 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
90 vendor->netid.next = &vendor->netid;
Simon Kelleyc72daea2012-01-05 21:33:27 +000091
Simon Kelleyfa785732016-07-22 20:56:01 +010092 reset_counter();
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010093 state.context = context;
94 state.interface = interface;
95 state.iface_name = iface_name;
96 state.fallback = fallback;
Simon Kelleyc3a04082014-01-11 22:18:19 +000097 state.ll_addr = ll_addr;
98 state.ula_addr = ula_addr;
Simon Kelley8939c952013-09-25 11:49:34 +010099 state.mac_len = 0;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100100 state.tags = NULL;
101 state.link_address = NULL;
102
Simon Kelley8939c952013-09-25 11:49:34 +0100103 if (dhcp6_maybe_relay(&state, daemon->dhcp_packet.iov_base, sz, client_addr,
104 IN6_IS_ADDR_MULTICAST(client_addr), now))
Simon Kelley1d0f91c2012-03-12 11:56:22 +0000105 return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000106
107 return 0;
108}
109
Simon Kelley4cb1b322012-02-06 14:30:41 +0000110/* This cost me blood to write, it will probably cost you blood to understand - srk. */
Simon Kelley8939c952013-09-25 11:49:34 +0100111static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
112 struct in6_addr *client_addr, int is_unicast, time_t now)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000113{
114 void *end = inbuff + sz;
115 void *opts = inbuff + 34;
116 int msg_type = *((unsigned char *)inbuff);
117 unsigned char *outmsgtypep;
118 void *opt;
119 struct dhcp_vendor *vendor;
120
Josh Soref730c6742017-02-06 16:14:04 +0000121 /* if not an encapsulated relayed message, just do the stuff */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000122 if (msg_type != DHCP6RELAYFORW)
123 {
124 /* if link_address != NULL if points to the link address field of the
125 innermost nested RELAYFORW message, which is where we find the
126 address of the network on which we can allocate an address.
Simon Kelley8939c952013-09-25 11:49:34 +0100127 Recalculate the available contexts using that information.
128
129 link_address == NULL means there's no relay in use, so we try and find the client's
130 MAC address from the local ND cache. */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000131
Simon Kelley8939c952013-09-25 11:49:34 +0100132 if (!state->link_address)
Simon Kelley33702ab2015-12-28 23:17:15 +0000133 get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type, now);
Simon Kelley8939c952013-09-25 11:49:34 +0100134 else
Simon Kelley4cb1b322012-02-06 14:30:41 +0000135 {
136 struct dhcp_context *c;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100137 state->context = NULL;
Simon Kelleybaeb3ad2013-01-10 11:47:38 +0000138
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100139 if (!IN6_IS_ADDR_LOOPBACK(state->link_address) &&
140 !IN6_IS_ADDR_LINKLOCAL(state->link_address) &&
141 !IN6_IS_ADDR_MULTICAST(state->link_address))
Simon Kelleybaeb3ad2013-01-10 11:47:38 +0000142 for (c = daemon->dhcp6; c; c = c->next)
143 if ((c->flags & CONTEXT_DHCP) &&
Simon Kelleyef1a94a2013-07-26 13:59:03 +0100144 !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100145 is_same_net6(state->link_address, &c->start6, c->prefix) &&
146 is_same_net6(state->link_address, &c->end6, c->prefix))
Simon Kelleybaeb3ad2013-01-10 11:47:38 +0000147 {
Simon Kelley8ac97872013-03-30 21:34:19 +0000148 c->preferred = c->valid = 0xffffffff;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100149 c->current = state->context;
150 state->context = c;
Simon Kelleybaeb3ad2013-01-10 11:47:38 +0000151 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000152
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100153 if (!state->context)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000154 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100155 inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000156 my_syslog(MS_DHCP | LOG_WARNING,
157 _("no address range available for DHCPv6 request from relay at %s"),
158 daemon->addrbuff);
159 return 0;
160 }
161 }
Simon Kelley8939c952013-09-25 11:49:34 +0100162
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100163 if (!state->context)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000164 {
165 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100166 _("no address range available for DHCPv6 request via %s"), state->iface_name);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000167 return 0;
168 }
169
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100170 return dhcp6_no_relay(state, msg_type, inbuff, sz, is_unicast, now);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000171 }
172
173 /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
174 which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
175 if (sz < 38)
176 return 0;
177
178 /* copy header stuff into reply message and set type to reply */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100179 if (!(outmsgtypep = put_opt6(inbuff, 34)))
180 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000181 *outmsgtypep = DHCP6RELAYREPL;
182
183 /* look for relay options and set tags if found. */
184 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
185 {
186 int mopt;
187
188 if (vendor->match_type == MATCH_SUBSCRIBER)
189 mopt = OPTION6_SUBSCRIBER_ID;
190 else if (vendor->match_type == MATCH_REMOTE)
191 mopt = OPTION6_REMOTE_ID;
192 else
193 continue;
194
195 if ((opt = opt6_find(opts, end, mopt, 1)) &&
196 vendor->len == opt6_len(opt) &&
197 memcmp(vendor->data, opt6_ptr(opt, 0), vendor->len) == 0 &&
198 vendor->netid.next != &vendor->netid)
199 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100200 vendor->netid.next = state->tags;
201 state->tags = &vendor->netid;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000202 break;
203 }
204 }
205
Simon Kelley89500e32013-09-20 16:29:20 +0100206 /* RFC-6939 */
207 if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3)))
208 {
Simon Kelley3d4ff1b2017-09-25 18:52:50 +0100209 if (opt6_len(opt) - 2 > DHCP_CHADDR_MAX) {
210 return 0;
211 }
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100212 state->mac_type = opt6_uint(opt, 0, 2);
213 state->mac_len = opt6_len(opt) - 2;
Simon Kelley8939c952013-09-25 11:49:34 +0100214 memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
Simon Kelley89500e32013-09-20 16:29:20 +0100215 }
216
Simon Kelley4cb1b322012-02-06 14:30:41 +0000217 for (opt = opts; opt; opt = opt6_next(opt, end))
218 {
yiwenchen499d8dd2018-02-14 22:26:54 +0000219 if (opt6_ptr(opt, 0) + opt6_len(opt) > end)
Simon Kelley33e3f102017-09-25 20:05:11 +0100220 return 0;
yiwenchen499d8dd2018-02-14 22:26:54 +0000221
Simon Kelley4cb1b322012-02-06 14:30:41 +0000222 int o = new_opt6(opt6_type(opt));
223 if (opt6_type(opt) == OPTION6_RELAY_MSG)
224 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100225 struct in6_addr align;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000226 /* the packet data is unaligned, copy to aligned storage */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100227 memcpy(&align, inbuff + 2, IN6ADDRSZ);
228 state->link_address = &align;
229 /* zero is_unicast since that is now known to refer to the
Simon Kelley4cb1b322012-02-06 14:30:41 +0000230 relayed packet, not the original sent by the client */
Simon Kelley8939c952013-09-25 11:49:34 +0100231 if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000232 return 0;
233 }
Simon Kelley89500e32013-09-20 16:29:20 +0100234 else if (opt6_type(opt) != OPTION6_CLIENT_MAC)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000235 put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
236 end_opt6(o);
237 }
238
239 return 1;
240}
241
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100242static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000243{
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000244 void *opt;
245 int i, o, o1, start_opts;
246 struct dhcp_opt *opt_cfg;
247 struct dhcp_netid *tagif;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000248 struct dhcp_config *config = NULL;
Simon Kelley0d28af82012-09-20 21:24:06 +0100249 struct dhcp_netid known_id, iface_id, v6_id;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000250 unsigned char *outmsgtypep;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000251 struct dhcp_vendor *vendor;
252 struct dhcp_context *context_tmp;
Simon Kelley89500e32013-09-20 16:29:20 +0100253 struct dhcp_mac *mac_opt;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000254 unsigned int ignore = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000255#ifdef OPTION6_PREFIX_CLASS
Simon Kelley6e37ab52013-03-19 20:50:11 +0000256 struct prefix_class *p;
257 int dump_all_prefix_classes = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000258#endif
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000259
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100260 state->packet_options = inbuff + 4;
261 state->end = inbuff + sz;
262 state->clid = NULL;
263 state->clid_len = 0;
264 state->lease_allocate = 0;
265 state->context_tags = NULL;
266 state->domain = NULL;
267 state->send_domain = NULL;
268 state->hostname_auth = 0;
269 state->hostname = NULL;
270 state->client_hostname = NULL;
Josh Soref730c6742017-02-06 16:14:04 +0000271 state->fqdn_flags = 0x01; /* default to send if we receive no FQDN option */
Simon Kelleyc6309242013-03-07 20:59:28 +0000272#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100273 state->send_prefix_class = NULL;
Simon Kelleyc6309242013-03-07 20:59:28 +0000274#endif
Simon Kelley4cb1b322012-02-06 14:30:41 +0000275
Simon Kelleyceae00d2012-02-09 21:28:14 +0000276 /* set tag with name == interface */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100277 iface_id.net = state->iface_name;
278 iface_id.next = state->tags;
279 state->tags = &iface_id;
Simon Kelleyceae00d2012-02-09 21:28:14 +0000280
Simon Kelley23780dd2012-10-23 17:04:37 +0100281 /* set tag "dhcpv6" */
282 v6_id.net = "dhcpv6";
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100283 v6_id.next = state->tags;
284 state->tags = &v6_id;
Simon Kelley0d28af82012-09-20 21:24:06 +0100285
Simon Kelley4cb1b322012-02-06 14:30:41 +0000286 /* copy over transaction-id, and save pointer to message type */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100287 if (!(outmsgtypep = put_opt6(inbuff, 4)))
288 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000289 start_opts = save_counter(-1);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100290 state->xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000291
292 /* We're going to be linking tags from all context we use.
293 mark them as unused so we don't link one twice and break the list */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100294 for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000295 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100296 context_tmp->netid.next = &context_tmp->netid;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000297
298 if (option_bool(OPT_LOG_OPTS))
299 {
300 inet_ntop(AF_INET6, &context_tmp->start6, daemon->dhcp_buff, ADDRSTRLEN);
301 inet_ntop(AF_INET6, &context_tmp->end6, daemon->dhcp_buff2, ADDRSTRLEN);
302 if (context_tmp->flags & (CONTEXT_STATIC))
303 my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCPv6 subnet: %s/%d"),
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100304 state->xid, daemon->dhcp_buff, context_tmp->prefix);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000305 else
306 my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"),
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100307 state->xid, daemon->dhcp_buff, daemon->dhcp_buff2);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000308 }
309 }
310
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100311 if ((opt = opt6_find(state->packet_options, state->end, OPTION6_CLIENT_ID, 1)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000312 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100313 state->clid = opt6_ptr(opt, 0);
314 state->clid_len = opt6_len(opt);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000315 o = new_opt6(OPTION6_CLIENT_ID);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100316 put_opt6(state->clid, state->clid_len);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000317 end_opt6(o);
318 }
319 else if (msg_type != DHCP6IREQ)
320 return 0;
321
Ilya Ponetaev7f68f822014-09-13 20:52:27 +0100322 /* server-id must match except for SOLICIT, CONFIRM and REBIND messages */
323 if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ && msg_type != DHCP6REBIND &&
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100324 (!(opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1)) ||
Simon Kelley4cb1b322012-02-06 14:30:41 +0000325 opt6_len(opt) != daemon->duid_len ||
326 memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
327 return 0;
328
329 o = new_opt6(OPTION6_SERVER_ID);
330 put_opt6(daemon->duid, daemon->duid_len);
331 end_opt6(o);
332
333 if (is_unicast &&
334 (msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
335
336 {
Ilya Ponetaev976afc92014-09-13 20:56:14 +0100337 *outmsgtypep = DHCP6REPLY;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000338 o1 = new_opt6(OPTION6_STATUS_CODE);
339 put_opt6_short(DHCP6USEMULTI);
340 put_opt6_string("Use multicast");
341 end_opt6(o1);
342 return 1;
343 }
344
345 /* match vendor and user class options */
346 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
347 {
348 int mopt;
349
350 if (vendor->match_type == MATCH_VENDOR)
351 mopt = OPTION6_VENDOR_CLASS;
352 else if (vendor->match_type == MATCH_USER)
353 mopt = OPTION6_USER_CLASS;
354 else
355 continue;
356
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100357 if ((opt = opt6_find(state->packet_options, state->end, mopt, 2)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000358 {
359 void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt));
Simon Kelleya5c72ab2012-02-10 13:42:47 +0000360 int offset = 0;
361
362 if (mopt == OPTION6_VENDOR_CLASS)
363 {
364 if (opt6_len(opt) < 4)
365 continue;
366
367 if (vendor->enterprise != opt6_uint(opt, 0, 4))
368 continue;
369
370 offset = 4;
371 }
372
Tanguy Bouzelocef1d7422013-10-03 11:06:31 +0100373 /* Note that format if user/vendor classes is different to DHCP options - no option types. */
374 for (enc_opt = opt6_ptr(opt, offset); enc_opt; enc_opt = opt6_user_vendor_next(enc_opt, enc_end))
375 for (i = 0; i <= (opt6_user_vendor_len(enc_opt) - vendor->len); i++)
376 if (memcmp(vendor->data, opt6_user_vendor_ptr(enc_opt, i), vendor->len) == 0)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000377 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100378 vendor->netid.next = state->tags;
379 state->tags = &vendor->netid;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000380 break;
381 }
382 }
383 }
Simon Kelley3634c542012-02-08 14:22:37 +0000384
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100385 if (option_bool(OPT_LOG_OPTS) && (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
386 my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %u"), state->xid, opt6_uint(opt, 0, 4));
Simon Kelley1567fea2012-03-12 22:15:35 +0000387
Simon Kelley3634c542012-02-08 14:22:37 +0000388 /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
389 Otherwise assume the option is an array, and look for a matching element.
Josh Soref730c6742017-02-06 16:14:04 +0000390 If no data given, existence of the option is enough. This code handles
Simon Kelley3634c542012-02-08 14:22:37 +0000391 V-I opts too. */
392 for (opt_cfg = daemon->dhcp_match6; opt_cfg; opt_cfg = opt_cfg->next)
393 {
Simon Kelleyceae00d2012-02-09 21:28:14 +0000394 int match = 0;
395
Simon Kelley3634c542012-02-08 14:22:37 +0000396 if (opt_cfg->flags & DHOPT_RFC3925)
397 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100398 for (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_OPTS, 4);
Simon Kelley3634c542012-02-08 14:22:37 +0000399 opt;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100400 opt = opt6_find(opt6_next(opt, state->end), state->end, OPTION6_VENDOR_OPTS, 4))
Simon Kelley3634c542012-02-08 14:22:37 +0000401 {
402 void *vopt;
403 void *vend = opt6_ptr(opt, opt6_len(opt));
404
405 for (vopt = opt6_find(opt6_ptr(opt, 4), vend, opt_cfg->opt, 0);
406 vopt;
407 vopt = opt6_find(opt6_next(vopt, vend), vend, opt_cfg->opt, 0))
Simon Kelleyceae00d2012-02-09 21:28:14 +0000408 if ((match = match_bytes(opt_cfg, opt6_ptr(vopt, 0), opt6_len(vopt))))
Simon Kelley3634c542012-02-08 14:22:37 +0000409 break;
410 }
411 if (match)
412 break;
413 }
414 else
415 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100416 if (!(opt = opt6_find(state->packet_options, state->end, opt_cfg->opt, 1)))
Simon Kelley3634c542012-02-08 14:22:37 +0000417 continue;
418
419 match = match_bytes(opt_cfg, opt6_ptr(opt, 0), opt6_len(opt));
420 }
421
422 if (match)
423 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100424 opt_cfg->netid->next = state->tags;
425 state->tags = opt_cfg->netid;
Simon Kelley3634c542012-02-08 14:22:37 +0000426 }
427 }
Simon Kelley89500e32013-09-20 16:29:20 +0100428
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100429 if (state->mac_len != 0)
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100430 {
431 if (option_bool(OPT_LOG_OPTS))
Simon Kelley89500e32013-09-20 16:29:20 +0100432 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100433 print_mac(daemon->dhcp_buff, state->mac, state->mac_len);
434 my_syslog(MS_DHCP | LOG_INFO, _("%u client MAC address: %s"), state->xid, daemon->dhcp_buff);
Simon Kelley89500e32013-09-20 16:29:20 +0100435 }
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100436
437 for (mac_opt = daemon->dhcp_macs; mac_opt; mac_opt = mac_opt->next)
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100438 if ((unsigned)mac_opt->hwaddr_len == state->mac_len &&
439 ((unsigned)mac_opt->hwaddr_type == state->mac_type || mac_opt->hwaddr_type == 0) &&
440 memcmp_masked(mac_opt->hwaddr, state->mac, state->mac_len, mac_opt->mask))
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100441 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100442 mac_opt->netid.next = state->tags;
443 state->tags = &mac_opt->netid;
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100444 }
445 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000446
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100447 if ((opt = opt6_find(state->packet_options, state->end, OPTION6_FQDN, 1)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000448 {
449 /* RFC4704 refers */
450 int len = opt6_len(opt) - 1;
451
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100452 state->fqdn_flags = opt6_uint(opt, 0, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000453
454 /* Always force update, since the client has no way to do it itself. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100455 if (!option_bool(OPT_FQDN_UPDATE) && !(state->fqdn_flags & 0x01))
456 state->fqdn_flags |= 0x03;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000457
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100458 state->fqdn_flags &= ~0x04;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000459
460 if (len != 0 && len < 255)
461 {
Simon Kelleyfbbc1452012-03-30 20:48:20 +0100462 unsigned char *pp, *op = opt6_ptr(opt, 1);
463 char *pq = daemon->dhcp_buff;
464
465 pp = op;
466 while (*op != 0 && ((op + (*op)) - pp) < len)
467 {
468 memcpy(pq, op+1, *op);
469 pq += *op;
470 op += (*op)+1;
471 *(pq++) = '.';
472 }
473
474 if (pq != daemon->dhcp_buff)
475 pq--;
476 *pq = 0;
477
478 if (legal_hostname(daemon->dhcp_buff))
479 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100480 state->client_hostname = daemon->dhcp_buff;
Simon Kelleyfbbc1452012-03-30 20:48:20 +0100481 if (option_bool(OPT_LOG_OPTS))
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100482 my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), state->xid, state->client_hostname);
Simon Kelleyfbbc1452012-03-30 20:48:20 +0100483 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000484 }
485 }
486
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100487 if (state->clid)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000488 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100489 config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000490
491 if (have_config(config, CONFIG_NAME))
492 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100493 state->hostname = config->hostname;
494 state->domain = config->domain;
495 state->hostname_auth = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000496 }
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100497 else if (state->client_hostname)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000498 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100499 state->domain = strip_hostname(state->client_hostname);
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000500
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100501 if (strlen(state->client_hostname) != 0)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000502 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100503 state->hostname = state->client_hostname;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000504 if (!config)
505 {
506 /* Search again now we have a hostname.
Simon Kelley00e9ad52012-02-16 21:53:11 +0000507 Only accept configs without CLID here, (it won't match)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000508 to avoid impersonation by name. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100509 struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000510 if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
511 config = new;
512 }
513 }
514 }
515 }
516
517 if (config)
518 {
519 struct dhcp_netid_list *list;
520
521 for (list = config->netid; list; list = list->next)
522 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100523 list->list->next = state->tags;
524 state->tags = list->list;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000525 }
526
527 /* set "known" tag for known hosts */
528 known_id.net = "known";
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100529 known_id.next = state->tags;
530 state->tags = &known_id;
Simon Kelley3634c542012-02-08 14:22:37 +0000531
532 if (have_config(config, CONFIG_DISABLE))
533 ignore = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000534 }
Simon Kelleyb2a9c572017-04-30 18:21:31 +0100535 else if (state->clid &&
536 find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL))
537 {
538 known_id.net = "known-othernet";
539 known_id.next = state->tags;
540 state->tags = &known_id;
541 }
542
Simon Kelleyc6309242013-03-07 20:59:28 +0000543#ifdef OPTION6_PREFIX_CLASS
Simon Kelley6e37ab52013-03-19 20:50:11 +0000544 /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
545 if (daemon->prefix_classes && (msg_type == DHCP6SOLICIT || msg_type == DHCP6REQUEST))
Simon Kelleyc6309242013-03-07 20:59:28 +0000546 {
Simon Kelley6e37ab52013-03-19 20:50:11 +0000547 void *oro;
548
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100549 if ((oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0)))
Simon Kelley6e37ab52013-03-19 20:50:11 +0000550 for (i = 0; i < opt6_len(oro) - 1; i += 2)
551 if (opt6_uint(oro, i, 2) == OPTION6_PREFIX_CLASS)
552 {
553 dump_all_prefix_classes = 1;
554 break;
555 }
556
557 if (msg_type != DHCP6SOLICIT || dump_all_prefix_classes)
558 /* Add the tags associated with prefix classes so we can use the DHCP ranges.
559 Not done for SOLICIT as we add them one-at-time. */
560 for (p = daemon->prefix_classes; p ; p = p->next)
561 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100562 p->tag.next = state->tags;
563 state->tags = &p->tag;
Simon Kelley6e37ab52013-03-19 20:50:11 +0000564 }
565 }
Simon Kelleyc6309242013-03-07 20:59:28 +0000566#endif
567
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100568 tagif = run_tag_if(state->tags);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000569
Simon Kelley3634c542012-02-08 14:22:37 +0000570 /* if all the netids in the ignore list are present, ignore this client */
571 if (daemon->dhcp_ignore)
572 {
573 struct dhcp_netid_list *id_list;
574
Simon Kelley3634c542012-02-08 14:22:37 +0000575 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
576 if (match_netid(id_list->list, tagif, 0))
577 ignore = 1;
578 }
Simon Kelley00e9ad52012-02-16 21:53:11 +0000579
580 /* if all the netids in the ignore_name list are present, ignore client-supplied name */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100581 if (!state->hostname_auth)
Simon Kelley00e9ad52012-02-16 21:53:11 +0000582 {
583 struct dhcp_netid_list *id_list;
584
585 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
586 if ((!id_list->list) || match_netid(id_list->list, tagif, 0))
587 break;
588 if (id_list)
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100589 state->hostname = NULL;
Simon Kelley00e9ad52012-02-16 21:53:11 +0000590 }
591
Simon Kelley4cb1b322012-02-06 14:30:41 +0000592
593 switch (msg_type)
594 {
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000595 default:
596 return 0;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100597
598
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000599 case DHCP6SOLICIT:
600 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000601 int address_assigned = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000602 /* tags without all prefix-class tags */
Simon Kelley8f51a292013-09-21 14:07:12 +0100603 struct dhcp_netid *solicit_tags;
Simon Kelleyde92b472013-03-15 18:25:10 +0000604 struct dhcp_context *c;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100605
606 *outmsgtypep = DHCP6ADVERTISE;
607
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100608 if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000609 {
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100610 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100611 state->lease_allocate = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000612 o = new_opt6(OPTION6_RAPID_COMMIT);
613 end_opt6(o);
614 }
Simon Kelley3634c542012-02-08 14:22:37 +0000615
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100616 log6_quiet(state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL);
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100617
618 request_no_address:
Simon Kelley8f51a292013-09-21 14:07:12 +0100619 solicit_tags = tagif;
620
Simon Kelley3634c542012-02-08 14:22:37 +0000621 if (ignore)
622 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000623
Simon Kelley52a1ae72013-03-06 22:43:26 +0000624 /* reset USED bits in leases */
625 lease6_reset();
Simon Kelleyde92b472013-03-15 18:25:10 +0000626
627 /* Can use configured address max once per prefix */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100628 for (c = state->context; c; c = c->current)
Simon Kelleyde92b472013-03-15 18:25:10 +0000629 c->flags &= ~CONTEXT_CONF_USED;
630
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100631 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000632 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000633 void *ia_option, *ia_end;
634 unsigned int min_time = 0xffffffff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000635 int t1cntr;
Simon Kelleyc6309242013-03-07 20:59:28 +0000636 int ia_counter;
637 /* set unless we're sending a particular prefix-class, when we
638 want only dhcp-ranges with the correct tags set and not those without any tags. */
639 int plain_range = 1;
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100640 u32 lease_time;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000641 struct dhcp_lease *ltmp;
642 struct in6_addr *req_addr;
643 struct in6_addr addr;
Simon Kelleyc6309242013-03-07 20:59:28 +0000644
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100645 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000646 continue;
647
Simon Kelley52a1ae72013-03-06 22:43:26 +0000648 /* reset USED bits in contexts - one address per prefix per IAID */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100649 for (c = state->context; c; c = c->current)
Simon Kelley52a1ae72013-03-06 22:43:26 +0000650 c->flags &= ~CONTEXT_USED;
Simon Kelleyc6309242013-03-07 20:59:28 +0000651
652#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100653 if (daemon->prefix_classes && state->ia_type == OPTION6_IA_NA)
Simon Kelleyc6309242013-03-07 20:59:28 +0000654 {
Simon Kelley6e37ab52013-03-19 20:50:11 +0000655 void *prefix_opt;
Simon Kelleyc6309242013-03-07 20:59:28 +0000656 int prefix_class;
657
Simon Kelley6e37ab52013-03-19 20:50:11 +0000658 if (dump_all_prefix_classes)
659 /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
660 plain_range = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000661 else
662 {
663 if ((prefix_opt = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_PREFIX_CLASS, 2)))
664 {
665
666 prefix_class = opt6_uint(prefix_opt, 0, 2);
667
668 for (p = daemon->prefix_classes; p ; p = p->next)
669 if (p->class == prefix_class)
670 break;
671
672 if (!p)
673 my_syslog(MS_DHCP | LOG_WARNING, _("unknown prefix-class %d"), prefix_class);
674 else
675 {
676 /* add tag to list, and exclude undecorated dhcp-ranges */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100677 p->tag.next = state->tags;
Simon Kelleyc6309242013-03-07 20:59:28 +0000678 solicit_tags = run_tag_if(&p->tag);
679 plain_range = 0;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100680 state->send_prefix_class = p;
Simon Kelleyc6309242013-03-07 20:59:28 +0000681 }
682 }
683 else
684 {
685 /* client didn't ask for a prefix class, lets see if we can find one. */
686 for (p = daemon->prefix_classes; p ; p = p->next)
687 {
688 p->tag.next = NULL;
689 if (match_netid(&p->tag, solicit_tags, 1))
690 break;
691 }
692
693 if (p)
694 {
695 plain_range = 0;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100696 state->send_prefix_class = p;
Simon Kelleyc6309242013-03-07 20:59:28 +0000697 }
698 }
699
700 if (p && option_bool(OPT_LOG_OPTS))
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100701 my_syslog(MS_DHCP | LOG_INFO, "%u prefix class %d tag:%s", state->xid, p->class, p->tag.net);
Simon Kelleyc6309242013-03-07 20:59:28 +0000702 }
703 }
704#endif
705
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100706 o = build_ia(state, &t1cntr);
Vladislav Grishenkob9ff5c82014-10-06 14:34:24 +0100707 if (address_assigned)
708 address_assigned = 2;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000709
Simon Kelleyc6309242013-03-07 20:59:28 +0000710 for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000711 {
712 req_addr = opt6_ptr(ia_option, 0);
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100713
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100714 if ((c = address6_valid(state->context, req_addr, solicit_tags, plain_range)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000715 {
716 lease_time = c->lease_time;
717 /* If the client asks for an address on the same network as a configured address,
718 offer the configured address instead, to make moving to newly-configured
719 addresses automatic. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100720 if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000721 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000722 req_addr = &addr;
723 mark_config_used(c, &addr);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000724 if (have_config(config, CONFIG_TIME))
725 lease_time = config->lease_time;
726 }
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100727 else if (!(c = address6_available(state->context, req_addr, solicit_tags, plain_range)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000728 continue; /* not an address we're allowed */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100729 else if (!check_address(state, req_addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000730 continue; /* address leased elsewhere */
731
732 /* add address to output packet */
Simon Kelleyc6309242013-03-07 20:59:28 +0000733#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100734 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
735 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000736#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100737 add_address(state, c, lease_time, ia_option, &min_time, req_addr, now);
738 mark_context_used(state, req_addr);
739 get_context_tag(state, c);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000740 address_assigned = 1;
741 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000742 }
743
Simon Kelleyde92b472013-03-15 18:25:10 +0000744 /* Suggest configured address(es) */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100745 for (c = state->context; c; c = c->current)
Simon Kelleya1a79ed2013-03-15 21:19:57 +0000746 if (!(c->flags & CONTEXT_CONF_USED) &&
747 match_netid(c->filter, solicit_tags, plain_range) &&
748 config_valid(config, c, &addr) &&
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100749 check_address(state, &addr))
Simon Kelleyde92b472013-03-15 18:25:10 +0000750 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100751 mark_config_used(state->context, &addr);
Simon Kelleyde92b472013-03-15 18:25:10 +0000752 if (have_config(config, CONFIG_TIME))
753 lease_time = config->lease_time;
Simon Kelleya1a79ed2013-03-15 21:19:57 +0000754 else
755 lease_time = c->lease_time;
Simon Kelleyde92b472013-03-15 18:25:10 +0000756 /* add address to output packet */
Simon Kelleyc6309242013-03-07 20:59:28 +0000757#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100758 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
759 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000760#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100761 add_address(state, c, lease_time, NULL, &min_time, &addr, now);
762 mark_context_used(state, &addr);
763 get_context_tag(state, c);
Simon Kelleyde92b472013-03-15 18:25:10 +0000764 address_assigned = 1;
765 }
766
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000767 /* return addresses for existing leases */
768 ltmp = NULL;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100769 while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000770 {
Simon Kelley89500e32013-09-20 16:29:20 +0100771 req_addr = &ltmp->addr6;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100772 if ((c = address6_available(state->context, req_addr, solicit_tags, plain_range)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000773 {
Simon Kelleyc6309242013-03-07 20:59:28 +0000774#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100775 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
776 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000777#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100778 add_address(state, c, c->lease_time, NULL, &min_time, req_addr, now);
779 mark_context_used(state, req_addr);
780 get_context_tag(state, c);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000781 address_assigned = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000782 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000783 }
784
785 /* Return addresses for all valid contexts which don't yet have one */
Simon Kelley6586e832013-11-07 14:20:13 +0000786 while ((c = address6_allocate(state->context, state->clid, state->clid_len, state->ia_type == OPTION6_IA_TA,
787 state->iaid, ia_counter, solicit_tags, plain_range, &addr)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000788 {
Simon Kelleyc6309242013-03-07 20:59:28 +0000789#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100790 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
791 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000792#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100793 add_address(state, c, c->lease_time, NULL, &min_time, &addr, now);
794 mark_context_used(state, &addr);
795 get_context_tag(state, c);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000796 address_assigned = 1;
797 }
798
Vladislav Grishenkob9ff5c82014-10-06 14:34:24 +0100799 if (address_assigned != 1)
800 {
801 /* If the server will not assign any addresses to any IAs in a
802 subsequent Request from the client, the server MUST send an Advertise
803 message to the client that doesn't include any IA options. */
804 if (!state->lease_allocate)
805 {
806 save_counter(o);
807 continue;
808 }
809
810 /* If the server cannot assign any addresses to an IA in the message
811 from the client, the server MUST include the IA in the Reply message
812 with no addresses in the IA and a Status Code option in the IA
813 containing status code NoAddrsAvail. */
814 o1 = new_opt6(OPTION6_STATUS_CODE);
815 put_opt6_short(DHCP6NOADDRS);
816 put_opt6_string(_("address unavailable"));
817 end_opt6(o1);
818 }
819
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000820 end_ia(t1cntr, min_time, 0);
821 end_opt6(o);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000822 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000823
824 if (address_assigned)
825 {
826 o1 = new_opt6(OPTION6_STATUS_CODE);
827 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000828 put_opt6_string(_("success"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000829 end_opt6(o1);
830
831 /* If --dhcp-authoritative is set, we can tell client not to wait for
832 other possible servers */
833 o = new_opt6(OPTION6_PREFERENCE);
834 put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0);
835 end_opt6(o);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100836 tagif = add_options(state, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000837 }
838 else
839 {
840 /* no address, return error */
841 o1 = new_opt6(OPTION6_STATUS_CODE);
842 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000843 put_opt6_string(_("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000844 end_opt6(o1);
Simon Kelley338b3402015-04-20 21:34:05 +0100845
846 /* Some clients will ask repeatedly when we're not giving
847 out addresses because we're in stateless mode. Avoid spamming
848 the log in that case. */
849 for (c = state->context; c; c = c->current)
850 if (!(c->flags & CONTEXT_RA_STATELESS))
851 {
852 log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
853 break;
854 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000855 }
856
Simon Kelley4cb1b322012-02-06 14:30:41 +0000857 break;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000858 }
859
860 case DHCP6REQUEST:
861 {
862 int address_assigned = 0;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100863 int start = save_counter(-1);
864
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000865 /* set reply message type */
866 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100867 state->lease_allocate = 1;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000868
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100869 log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000870
871 if (ignore)
872 return 0;
873
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100874 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000875 {
876 void *ia_option, *ia_end;
877 unsigned int min_time = 0xffffffff;
878 int t1cntr;
879
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100880 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley3a654c52013-03-06 22:17:48 +0000881 continue;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100882
883 if (!ia_option)
884 {
Ville Skyttäfaaf3062018-01-14 17:32:52 +0000885 /* If we get a request with an IA_*A without addresses, treat it exactly like
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100886 a SOLICT with rapid commit set. */
887 save_counter(start);
888 goto request_no_address;
889 }
890
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100891 o = build_ia(state, &t1cntr);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000892
893 for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
894 {
895 struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000896 struct dhcp_context *dynamic, *c;
897 unsigned int lease_time;
Simon Kelleyde92b472013-03-15 18:25:10 +0000898 struct in6_addr addr;
899 int config_ok = 0;
900
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100901 if ((c = address6_valid(state->context, req_addr, tagif, 1)))
Simon Kelleyde92b472013-03-15 18:25:10 +0000902 config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr);
903
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100904 if ((dynamic = address6_available(state->context, req_addr, tagif, 1)) || c)
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000905 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000906 if (!dynamic && !config_ok)
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000907 {
908 /* Static range, not configured. */
909 o1 = new_opt6(OPTION6_STATUS_CODE);
Vladislav Grishenkob9ff5c82014-10-06 14:34:24 +0100910 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000911 put_opt6_string(_("address unavailable"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000912 end_opt6(o1);
913 }
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100914 else if (!check_address(state, req_addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000915 {
916 /* Address leased to another DUID/IAID */
917 o1 = new_opt6(OPTION6_STATUS_CODE);
918 put_opt6_short(DHCP6UNSPEC);
Simon Kelleyde92b472013-03-15 18:25:10 +0000919 put_opt6_string(_("address in use"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000920 end_opt6(o1);
921 }
922 else
923 {
924 if (!dynamic)
925 dynamic = c;
926
927 lease_time = dynamic->lease_time;
928
Simon Kelleyde92b472013-03-15 18:25:10 +0000929 if (config_ok && have_config(config, CONFIG_TIME))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000930 lease_time = config->lease_time;
931
Simon Kelley6e37ab52013-03-19 20:50:11 +0000932#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100933 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
934 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelley6e37ab52013-03-19 20:50:11 +0000935#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100936 add_address(state, dynamic, lease_time, ia_option, &min_time, req_addr, now);
937 get_context_tag(state, dynamic);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000938 address_assigned = 1;
939 }
940 }
Simon Kelleyde92b472013-03-15 18:25:10 +0000941 else
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000942 {
943 /* requested address not on the correct link */
944 o1 = new_opt6(OPTION6_STATUS_CODE);
945 put_opt6_short(DHCP6NOTONLINK);
Simon Kelleyde92b472013-03-15 18:25:10 +0000946 put_opt6_string(_("not on link"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000947 end_opt6(o1);
948 }
949 }
950
951 end_ia(t1cntr, min_time, 0);
952 end_opt6(o);
953 }
954
955 if (address_assigned)
956 {
957 o1 = new_opt6(OPTION6_STATUS_CODE);
958 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000959 put_opt6_string(_("success"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000960 end_opt6(o1);
961 }
962 else
963 {
964 /* no address, return error */
965 o1 = new_opt6(OPTION6_STATUS_CODE);
966 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000967 put_opt6_string(_("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000968 end_opt6(o1);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100969 log6_packet(state, "DHCPREPLY", NULL, _("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000970 }
971
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100972 tagif = add_options(state, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000973 break;
974 }
975
976
Simon Kelley4cb1b322012-02-06 14:30:41 +0000977 case DHCP6RENEW:
978 {
979 /* set reply message type */
980 *outmsgtypep = DHCP6REPLY;
981
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100982 log6_quiet(state, "DHCPRENEW", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000983
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100984 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000985 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000986 void *ia_option, *ia_end;
987 unsigned int min_time = 0xffffffff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000988 int t1cntr, iacntr;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000989
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100990 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000991 continue;
992
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100993 o = build_ia(state, &t1cntr);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000994 iacntr = save_counter(-1);
995
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000996 for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000997 {
998 struct dhcp_lease *lease = NULL;
999 struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001000 unsigned int preferred_time = opt6_uint(ia_option, 16, 4);
1001 unsigned int valid_time = opt6_uint(ia_option, 20, 4);
Simon Kelleyde92b472013-03-15 18:25:10 +00001002 char *message = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001003 struct dhcp_context *this_context;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001004
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001005 if (!(lease = lease6_find(state->clid, state->clid_len,
1006 state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
1007 state->iaid, req_addr)))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001008 {
1009 /* If the server cannot find a client entry for the IA the server
1010 returns the IA containing no addresses with a Status Code option set
1011 to NoBinding in the Reply message. */
1012 save_counter(iacntr);
1013 t1cntr = 0;
1014
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001015 log6_packet(state, "DHCPREPLY", req_addr, _("lease not found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001016
1017 o1 = new_opt6(OPTION6_STATUS_CODE);
1018 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001019 put_opt6_string(_("no binding found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001020 end_opt6(o1);
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001021
1022 preferred_time = valid_time = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001023 break;
1024 }
1025
Simon Kelley00e9ad52012-02-16 21:53:11 +00001026
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001027 if ((this_context = address6_available(state->context, req_addr, tagif, 1)) ||
1028 (this_context = address6_valid(state->context, req_addr, tagif, 1)))
Simon Kelleyc8257542012-03-28 21:15:41 +01001029 {
Simon Kelleyde92b472013-03-15 18:25:10 +00001030 struct in6_addr addr;
1031 unsigned int lease_time;
1032
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001033 get_context_tag(state, this_context);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001034
Simon Kelleyde92b472013-03-15 18:25:10 +00001035 if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))
1036 lease_time = config->lease_time;
1037 else
1038 lease_time = this_context->lease_time;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001039
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001040 calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001041
Simon Kelleyde92b472013-03-15 18:25:10 +00001042 lease_set_expires(lease, valid_time, now);
Simon Kelley89500e32013-09-20 16:29:20 +01001043 /* Update MAC record in case it's new information. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001044 if (state->mac_len != 0)
1045 lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
1046 if (state->ia_type == OPTION6_IA_NA && state->hostname)
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001047 {
1048 char *addr_domain = get_domain6(req_addr);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001049 if (!state->send_domain)
1050 state->send_domain = addr_domain;
1051 lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
1052 message = state->hostname;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001053 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001054
Simon Kelleyde92b472013-03-15 18:25:10 +00001055
1056 if (preferred_time == 0)
1057 message = _("deprecated");
Simon Kelley4cb1b322012-02-06 14:30:41 +00001058 }
Simon Kelleyde92b472013-03-15 18:25:10 +00001059 else
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001060 {
1061 preferred_time = valid_time = 0;
1062 message = _("address invalid");
Simon Kelleya5ae1f82015-04-25 21:46:10 +01001063 }
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001064
Simon Kelleya5ae1f82015-04-25 21:46:10 +01001065 if (message && (message != state->hostname))
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001066 log6_packet(state, "DHCPREPLY", req_addr, message);
1067 else
1068 log6_quiet(state, "DHCPREPLY", req_addr, message);
1069
Simon Kelley4cb1b322012-02-06 14:30:41 +00001070 o1 = new_opt6(OPTION6_IAADDR);
1071 put_opt6(req_addr, sizeof(*req_addr));
Simon Kelleyde92b472013-03-15 18:25:10 +00001072 put_opt6_long(preferred_time);
1073 put_opt6_long(valid_time);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001074 end_opt6(o1);
1075 }
1076
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001077 end_ia(t1cntr, min_time, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001078 end_opt6(o);
1079 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001080
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001081 tagif = add_options(state, 0);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001082 break;
1083
1084 }
1085
1086 case DHCP6CONFIRM:
1087 {
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001088 int good_addr = 0;
1089
Simon Kelley4cb1b322012-02-06 14:30:41 +00001090 /* set reply message type */
1091 *outmsgtypep = DHCP6REPLY;
1092
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001093 log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001094
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001095 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001096 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001097 void *ia_option, *ia_end;
1098
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001099 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001100 ia_option;
1101 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
1102 {
1103 struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
1104
Simon Kelley89130d92015-06-03 22:30:59 +01001105 if (!address6_valid(state->context, req_addr, tagif, 1))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001106 {
1107 o1 = new_opt6(OPTION6_STATUS_CODE);
1108 put_opt6_short(DHCP6NOTONLINK);
Simon Kelleyde92b472013-03-15 18:25:10 +00001109 put_opt6_string(_("confirm failed"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001110 end_opt6(o1);
Simon Kelleyc851c692018-07-20 17:35:24 +01001111 log6_quiet(state, "DHCPREPLY", req_addr, _("confirm failed"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001112 return 1;
1113 }
1114
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001115 good_addr = 1;
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001116 log6_quiet(state, "DHCPREPLY", req_addr, state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001117 }
1118 }
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001119
1120 /* No addresses, no reply: RFC 3315 18.2.2 */
1121 if (!good_addr)
1122 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001123
1124 o1 = new_opt6(OPTION6_STATUS_CODE);
1125 put_opt6_short(DHCP6SUCCESS );
Simon Kelleyde92b472013-03-15 18:25:10 +00001126 put_opt6_string(_("all addresses still on link"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001127 end_opt6(o1);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001128 break;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001129 }
1130
1131 case DHCP6IREQ:
1132 {
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001133 /* We can't discriminate contexts based on address, as we don't know it.
1134 If there is only one possible context, we can use its tags */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001135 if (state->context && state->context->netid.net && !state->context->current)
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001136 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001137 state->context->netid.next = NULL;
1138 state->context_tags = &state->context->netid;
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001139 }
Simon Kelley6bd109a2013-07-27 15:11:44 +01001140
1141 /* Similarly, we can't determine domain from address, but if the FQDN is
1142 given in --dhcp-host, we can use that, and failing that we can use the
1143 unqualified configured domain, if any. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001144 if (state->hostname_auth)
1145 state->send_domain = state->domain;
Simon Kelley6bd109a2013-07-27 15:11:44 +01001146 else
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001147 state->send_domain = get_domain6(NULL);
Simon Kelley6bd109a2013-07-27 15:11:44 +01001148
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001149 log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname);
Simon Kelley3634c542012-02-08 14:22:37 +00001150 if (ignore)
1151 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001152 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001153 tagif = add_options(state, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001154 break;
1155 }
1156
1157
1158 case DHCP6RELEASE:
1159 {
1160 /* set reply message type */
1161 *outmsgtypep = DHCP6REPLY;
1162
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001163 log6_quiet(state, "DHCPRELEASE", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001164
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001165 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001166 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001167 void *ia_option, *ia_end;
1168 int made_ia = 0;
1169
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001170 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001171 ia_option;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001172 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001173 {
1174 struct dhcp_lease *lease;
1175
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001176 if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
1177 state->iaid, opt6_ptr(ia_option, 0))))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001178 lease_prune(lease, now);
1179 else
1180 {
1181 if (!made_ia)
1182 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001183 o = new_opt6(state->ia_type);
1184 put_opt6_long(state->iaid);
1185 if (state->ia_type == OPTION6_IA_NA)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001186 {
1187 put_opt6_long(0);
1188 put_opt6_long(0);
1189 }
1190 made_ia = 1;
1191 }
1192
1193 o1 = new_opt6(OPTION6_IAADDR);
1194 put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
1195 put_opt6_long(0);
1196 put_opt6_long(0);
1197 end_opt6(o1);
1198 }
1199 }
1200
1201 if (made_ia)
1202 {
1203 o1 = new_opt6(OPTION6_STATUS_CODE);
1204 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001205 put_opt6_string(_("no binding found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001206 end_opt6(o1);
1207
1208 end_opt6(o);
1209 }
1210 }
1211
1212 o1 = new_opt6(OPTION6_STATUS_CODE);
1213 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +00001214 put_opt6_string(_("release received"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001215 end_opt6(o1);
1216
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001217 break;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001218 }
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001219
1220 case DHCP6DECLINE:
1221 {
1222 /* set reply message type */
1223 *outmsgtypep = DHCP6REPLY;
1224
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001225 log6_quiet(state, "DHCPDECLINE", NULL, NULL);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001226
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001227 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001228 {
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001229 void *ia_option, *ia_end;
1230 int made_ia = 0;
1231
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001232 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001233 ia_option;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001234 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001235 {
1236 struct dhcp_lease *lease;
1237 struct in6_addr *addrp = opt6_ptr(ia_option, 0);
1238
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001239 if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, addrp))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001240 {
Simon Kelleyceae00d2012-02-09 21:28:14 +00001241 prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001242 inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN);
1243 my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
Simon Kelleyceae00d2012-02-09 21:28:14 +00001244 daemon->addrbuff, daemon->dhcp_buff3);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001245 config->flags |= CONFIG_DECLINED;
1246 config->decline_time = now;
1247 }
1248 else
1249 /* make sure this host gets a different address next time. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001250 for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
1251 context_tmp->addr_epoch++;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001252
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001253 if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
1254 state->iaid, opt6_ptr(ia_option, 0))))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001255 lease_prune(lease, now);
1256 else
1257 {
1258 if (!made_ia)
1259 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001260 o = new_opt6(state->ia_type);
1261 put_opt6_long(state->iaid);
1262 if (state->ia_type == OPTION6_IA_NA)
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001263 {
1264 put_opt6_long(0);
1265 put_opt6_long(0);
1266 }
1267 made_ia = 1;
1268 }
1269
1270 o1 = new_opt6(OPTION6_IAADDR);
1271 put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
1272 put_opt6_long(0);
1273 put_opt6_long(0);
1274 end_opt6(o1);
1275 }
1276 }
1277
1278 if (made_ia)
1279 {
1280 o1 = new_opt6(OPTION6_STATUS_CODE);
1281 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001282 put_opt6_string(_("no binding found"));
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001283 end_opt6(o1);
1284
1285 end_opt6(o);
1286 }
1287
1288 }
Ilya Ponetaev51943362014-09-13 21:19:01 +01001289
Josh Soref730c6742017-02-06 16:14:04 +00001290 /* We must answer with 'success' in global section anyway */
Ilya Ponetaev51943362014-09-13 21:19:01 +01001291 o1 = new_opt6(OPTION6_STATUS_CODE);
1292 put_opt6_short(DHCP6SUCCESS);
1293 put_opt6_string(_("success"));
1294 end_opt6(o1);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001295 break;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001296 }
1297
Simon Kelley4cb1b322012-02-06 14:30:41 +00001298 }
1299
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001300 log_tags(tagif, state->xid);
1301 log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001302
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001303 return 1;
1304
1305}
1306
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001307static struct dhcp_netid *add_options(struct state *state, int do_refresh)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001308{
Simon Kelley2763d4b2013-03-06 21:24:56 +00001309 void *oro;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001310 /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001311 struct dhcp_netid *tagif = option_filter(state->tags, state->context_tags, daemon->dhcp_opts6);
1312 struct dhcp_opt *opt_cfg;
Simon Kelley871d4562013-07-27 21:32:32 +01001313 int done_dns = 0, done_refresh = !do_refresh, do_encap = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001314 int i, o, o1;
1315
1316 oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001317
1318 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1319 {
1320 /* netids match and not encapsulated? */
1321 if (!(opt_cfg->flags & DHOPT_TAGOK))
1322 continue;
1323
1324 if (!(opt_cfg->flags & DHOPT_FORCE) && oro)
1325 {
1326 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1327 if (opt6_uint(oro, i, 2) == (unsigned)opt_cfg->opt)
1328 break;
1329
1330 /* option not requested */
1331 if (i >= opt6_len(oro) - 1)
1332 continue;
1333 }
1334
Simon Kelley871d4562013-07-27 21:32:32 +01001335 if (opt_cfg->opt == OPTION6_REFRESH_TIME)
1336 done_refresh = 1;
Simon Kelley5e3e4642015-08-25 23:08:39 +01001337
1338 if (opt_cfg->opt == OPTION6_DNS_SERVER)
1339 done_dns = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001340
Simon Kelley27b78d92015-09-26 21:40:45 +01001341 if (opt_cfg->flags & DHOPT_ADDR6)
Simon Kelley4b86b652012-02-29 11:45:37 +00001342 {
Simon Kelleyc3a04082014-01-11 22:18:19 +00001343 int len, j;
1344 struct in6_addr *a;
1345
Simon Kelleyc3a04082014-01-11 22:18:19 +00001346 for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0;
1347 j < opt_cfg->len; j += IN6ADDRSZ, a++)
1348 if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
1349 (IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)))
1350 len -= IN6ADDRSZ;
1351
1352 if (len != 0)
1353 {
1354
1355 o = new_opt6(opt_cfg->opt);
1356
1357 for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
1358 {
1359 if (IN6_IS_ADDR_UNSPECIFIED(a))
1360 {
1361 if (!add_local_addrs(state->context))
1362 put_opt6(state->fallback, IN6ADDRSZ);
1363 }
1364 else if (IN6_IS_ADDR_ULA_ZERO(a))
1365 {
1366 if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))
1367 put_opt6(state->ula_addr, IN6ADDRSZ);
1368 }
1369 else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
1370 {
1371 if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
1372 put_opt6(state->ll_addr, IN6ADDRSZ);
1373 }
1374 else
1375 put_opt6(a, IN6ADDRSZ);
Simon Kelley4b86b652012-02-29 11:45:37 +00001376 }
Simon Kelleyc3a04082014-01-11 22:18:19 +00001377
1378 end_opt6(o);
1379 }
Simon Kelley4b86b652012-02-29 11:45:37 +00001380 }
Simon Kelleyc3a04082014-01-11 22:18:19 +00001381 else
1382 {
1383 o = new_opt6(opt_cfg->opt);
1384 if (opt_cfg->val)
1385 put_opt6(opt_cfg->val, opt_cfg->len);
1386 end_opt6(o);
1387 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001388 }
1389
Simon Kelley871d4562013-07-27 21:32:32 +01001390 if (daemon->port == NAMESERVER_PORT && !done_dns)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001391 {
1392 o = new_opt6(OPTION6_DNS_SERVER);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001393 if (!add_local_addrs(state->context))
1394 put_opt6(state->fallback, IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001395 end_opt6(o);
1396 }
Simon Kelley871d4562013-07-27 21:32:32 +01001397
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001398 if (state->context && !done_refresh)
Simon Kelley871d4562013-07-27 21:32:32 +01001399 {
1400 struct dhcp_context *c;
1401 unsigned int lease_time = 0xffffffff;
1402
1403 /* Find the smallest lease tie of all contexts,
Josh Soref730c6742017-02-06 16:14:04 +00001404 subject to the RFC-4242 stipulation that this must not
Simon Kelley871d4562013-07-27 21:32:32 +01001405 be less than 600. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001406 for (c = state->context; c; c = c->next)
Simon Kelley871d4562013-07-27 21:32:32 +01001407 if (c->lease_time < lease_time)
1408 {
1409 if (c->lease_time < 600)
1410 lease_time = 600;
1411 else
1412 lease_time = c->lease_time;
1413 }
1414
1415 o = new_opt6(OPTION6_REFRESH_TIME);
1416 put_opt6_long(lease_time);
1417 end_opt6(o);
1418 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001419
1420 /* handle vendor-identifying vendor-encapsulated options,
1421 dhcp-option = vi-encap:13,17,....... */
1422 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1423 opt_cfg->flags &= ~DHOPT_ENCAP_DONE;
Simon Kelley4b86b652012-02-29 11:45:37 +00001424
Simon Kelley4cb1b322012-02-06 14:30:41 +00001425 if (oro)
1426 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1427 if (opt6_uint(oro, i, 2) == OPTION6_VENDOR_OPTS)
1428 do_encap = 1;
1429
1430 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1431 {
1432 if (opt_cfg->flags & DHOPT_RFC3925)
1433 {
1434 int found = 0;
1435 struct dhcp_opt *oc;
1436
1437 if (opt_cfg->flags & DHOPT_ENCAP_DONE)
1438 continue;
1439
1440 for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1441 {
1442 oc->flags &= ~DHOPT_ENCAP_MATCH;
1443
1444 if (!(oc->flags & DHOPT_RFC3925) || opt_cfg->u.encap != oc->u.encap)
1445 continue;
1446
1447 oc->flags |= DHOPT_ENCAP_DONE;
1448 if (match_netid(oc->netid, tagif, 1))
1449 {
1450 /* option requested/forced? */
1451 if (!oro || do_encap || (oc->flags & DHOPT_FORCE))
1452 {
1453 oc->flags |= DHOPT_ENCAP_MATCH;
1454 found = 1;
1455 }
1456 }
1457 }
1458
1459 if (found)
1460 {
1461 o = new_opt6(OPTION6_VENDOR_OPTS);
1462 put_opt6_long(opt_cfg->u.encap);
1463
1464 for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1465 if (oc->flags & DHOPT_ENCAP_MATCH)
1466 {
1467 o1 = new_opt6(oc->opt);
1468 put_opt6(oc->val, oc->len);
1469 end_opt6(o1);
1470 }
1471 end_opt6(o);
1472 }
1473 }
1474 }
Simon Kelley07933802012-02-14 20:55:25 +00001475
1476
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001477 if (state->hostname)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001478 {
1479 unsigned char *p;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001480 size_t len = strlen(state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001481
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001482 if (state->send_domain)
Roy Marples3f3adae2013-07-25 16:22:46 +01001483 len += strlen(state->send_domain) + 2;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001484
1485 o = new_opt6(OPTION6_FQDN);
Roy Marples3f3adae2013-07-25 16:22:46 +01001486 if ((p = expand(len + 2)))
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001487 {
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001488 *(p++) = state->fqdn_flags;
Simon Kelley0549c732017-09-25 18:17:11 +01001489 p = do_rfc1035_name(p, state->hostname, NULL);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001490 if (state->send_domain)
Roy Marples3f3adae2013-07-25 16:22:46 +01001491 {
Simon Kelley0549c732017-09-25 18:17:11 +01001492 p = do_rfc1035_name(p, state->send_domain, NULL);
Roy Marples3f3adae2013-07-25 16:22:46 +01001493 *p = 0;
1494 }
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001495 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001496 end_opt6(o);
1497 }
1498
1499
1500 /* logging */
1501 if (option_bool(OPT_LOG_OPTS) && oro)
1502 {
1503 char *q = daemon->namebuff;
1504 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1505 {
1506 char *s = option_string(AF_INET6, opt6_uint(oro, i, 2), NULL, 0, NULL, 0);
1507 q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
1508 "%d%s%s%s",
1509 opt6_uint(oro, i, 2),
1510 strlen(s) != 0 ? ":" : "",
1511 s,
1512 (i > opt6_len(oro) - 3) ? "" : ", ");
1513 if ( i > opt6_len(oro) - 3 || (q - daemon->namebuff) > 40)
1514 {
1515 q = daemon->namebuff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001516 my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), state->xid, daemon->namebuff);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001517 }
1518 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001519 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001520
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001521 return tagif;
1522}
1523
1524static int add_local_addrs(struct dhcp_context *context)
1525{
1526 int done = 0;
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001527
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001528 for (; context; context = context->current)
1529 if ((context->flags & CONTEXT_USED) && !IN6_IS_ADDR_UNSPECIFIED(&context->local6))
1530 {
1531 /* squash duplicates */
1532 struct dhcp_context *c;
1533 for (c = context->current; c; c = c->current)
1534 if ((c->flags & CONTEXT_USED) &&
1535 IN6_ARE_ADDR_EQUAL(&context->local6, &c->local6))
1536 break;
1537
1538 if (!c)
1539 {
1540 done = 1;
1541 put_opt6(&context->local6, IN6ADDRSZ);
1542 }
1543 }
1544
1545 return done;
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001546}
1547
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001548
1549static void get_context_tag(struct state *state, struct dhcp_context *context)
1550{
1551 /* get tags from context if we've not used it before */
1552 if (context->netid.next == &context->netid && context->netid.net)
1553 {
1554 context->netid.next = state->context_tags;
1555 state->context_tags = &context->netid;
1556 if (!state->hostname_auth)
1557 {
1558 struct dhcp_netid_list *id_list;
1559
1560 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1561 if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1562 break;
1563 if (id_list)
1564 state->hostname = NULL;
1565 }
1566 }
1567}
Simon Kelleyc6309242013-03-07 20:59:28 +00001568
1569#ifdef OPTION6_PREFIX_CLASS
1570static struct prefix_class *prefix_class_from_context(struct dhcp_context *context)
1571{
1572 struct prefix_class *p;
1573 struct dhcp_netid *t;
1574
1575 for (p = daemon->prefix_classes; p ; p = p->next)
1576 for (t = context->filter; t; t = t->next)
1577 if (strcmp(p->tag.net, t->net) == 0)
1578 return p;
1579
1580 return NULL;
1581}
1582#endif
1583
Simon Kelley3a654c52013-03-06 22:17:48 +00001584static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001585{
1586 state->ia_type = opt6_type(opt);
Simon Kelley3a654c52013-03-06 22:17:48 +00001587 *ia_option = NULL;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001588
1589 if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
Simon Kelley3a654c52013-03-06 22:17:48 +00001590 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001591
1592 if (state->ia_type == OPTION6_IA_NA && opt6_len(opt) < 12)
Simon Kelley3a654c52013-03-06 22:17:48 +00001593 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001594
1595 if (state->ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
Simon Kelley3a654c52013-03-06 22:17:48 +00001596 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001597
1598 *endp = opt6_ptr(opt, opt6_len(opt));
1599 state->iaid = opt6_uint(opt, 0, 4);
Simon Kelley3a654c52013-03-06 22:17:48 +00001600 *ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
1601
1602 return 1;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001603}
1604
1605
1606static int build_ia(struct state *state, int *t1cntr)
1607{
1608 int o = new_opt6(state->ia_type);
1609
1610 put_opt6_long(state->iaid);
1611 *t1cntr = 0;
1612
1613 if (state->ia_type == OPTION6_IA_NA)
1614 {
1615 /* save pointer */
1616 *t1cntr = save_counter(-1);
1617 /* so we can fill these in later */
1618 put_opt6_long(0);
1619 put_opt6_long(0);
1620 }
1621
1622 return o;
1623}
1624
1625static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
1626{
1627 if (t1cntr != 0)
1628 {
Ville Skyttäfaaf3062018-01-14 17:32:52 +00001629 /* go back and fill in fields in IA_NA option */
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001630 int sav = save_counter(t1cntr);
1631 unsigned int t1, t2, fuzz = 0;
1632
1633 if (do_fuzz)
1634 {
1635 fuzz = rand16();
1636
1637 while (fuzz > (min_time/16))
1638 fuzz = fuzz/2;
1639 }
1640
1641 t1 = (min_time == 0xffffffff) ? 0xffffffff : min_time/2 - fuzz;
1642 t2 = (min_time == 0xffffffff) ? 0xffffffff : ((min_time/8)*7) - fuzz;
1643 put_opt6_long(t1);
1644 put_opt6_long(t2);
1645 save_counter(sav);
1646 }
1647}
1648
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001649static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
Simon Kelleyc8f2dd82013-09-13 11:22:55 +01001650 unsigned int *min_time, struct in6_addr *addr, time_t now)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001651{
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001652 unsigned int valid_time = 0, preferred_time = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001653 int o = new_opt6(OPTION6_IAADDR);
1654 struct dhcp_lease *lease;
1655
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001656 /* get client requested times */
1657 if (ia_option)
1658 {
1659 preferred_time = opt6_uint(ia_option, 16, 4);
1660 valid_time = opt6_uint(ia_option, 20, 4);
1661 }
1662
1663 calculate_times(context, min_time, &valid_time, &preferred_time, lease_time);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001664
Simon Kelleyde92b472013-03-15 18:25:10 +00001665 put_opt6(addr, sizeof(*addr));
1666 put_opt6_long(preferred_time);
1667 put_opt6_long(valid_time);
1668
Simon Kelleyc6309242013-03-07 20:59:28 +00001669#ifdef OPTION6_PREFIX_CLASS
1670 if (state->send_prefix_class)
1671 {
1672 int o1 = new_opt6(OPTION6_PREFIX_CLASS);
1673 put_opt6_short(state->send_prefix_class->class);
1674 end_opt6(o1);
1675 }
1676#endif
1677
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001678 end_opt6(o);
1679
Simon Kelleyc8f2dd82013-09-13 11:22:55 +01001680 if (state->lease_allocate)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001681 update_leases(state, context, addr, valid_time, now);
1682
1683 if ((lease = lease6_find_by_addr(addr, 128, 0)))
1684 lease->flags |= LEASE_USED;
1685
1686 /* get tags from context if we've not used it before */
1687 if (context->netid.next == &context->netid && context->netid.net)
1688 {
1689 context->netid.next = state->context_tags;
1690 state->context_tags = &context->netid;
1691
1692 if (!state->hostname_auth)
1693 {
1694 struct dhcp_netid_list *id_list;
1695
1696 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1697 if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1698 break;
1699 if (id_list)
1700 state->hostname = NULL;
1701 }
1702 }
1703
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001704 log6_quiet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001705
1706}
Simon Kelleyff59fc82013-03-07 11:00:26 +00001707
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001708static void mark_context_used(struct state *state, struct in6_addr *addr)
Simon Kelleyff59fc82013-03-07 11:00:26 +00001709{
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001710 struct dhcp_context *context;
1711
Simon Kelleyff59fc82013-03-07 11:00:26 +00001712 /* Mark that we have an address for this prefix. */
Simon Kelleyc6309242013-03-07 20:59:28 +00001713#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001714 for (context = state->context; context; context = context->current)
Simon Kelleyc6309242013-03-07 20:59:28 +00001715 if (is_same_net6(addr, &context->start6, context->prefix) &&
1716 (!state->send_prefix_class || state->send_prefix_class == prefix_class_from_context(context)))
1717 context->flags |= CONTEXT_USED;
1718#else
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001719 for (context = state->context; context; context = context->current)
Simon Kelleyff59fc82013-03-07 11:00:26 +00001720 if (is_same_net6(addr, &context->start6, context->prefix))
1721 context->flags |= CONTEXT_USED;
Simon Kelleyc6309242013-03-07 20:59:28 +00001722#endif
Simon Kelleyff59fc82013-03-07 11:00:26 +00001723}
Simon Kelleyc6309242013-03-07 20:59:28 +00001724
Simon Kelleyde92b472013-03-15 18:25:10 +00001725static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)
1726{
1727 for (; context; context = context->current)
1728 if (is_same_net6(addr, &context->start6, context->prefix))
1729 context->flags |= CONTEXT_CONF_USED;
1730}
1731
1732/* make sure address not leased to another CLID/IAID */
1733static int check_address(struct state *state, struct in6_addr *addr)
1734{
1735 struct dhcp_lease *lease;
1736
1737 if (!(lease = lease6_find_by_addr(addr, 128, 0)))
1738 return 1;
1739
1740 if (lease->clid_len != state->clid_len ||
1741 memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
Simon Kelley89500e32013-09-20 16:29:20 +01001742 lease->iaid != state->iaid)
Simon Kelleyde92b472013-03-15 18:25:10 +00001743 return 0;
1744
1745 return 1;
1746}
1747
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001748
1749/* Calculate valid and preferred times to send in leases/renewals.
1750
1751 Inputs are:
1752
1753 *valid_timep, *preferred_timep - requested times from IAADDR options.
1754 context->valid, context->preferred - times associated with subnet address on local interface.
1755 context->flags | CONTEXT_DEPRECATE - "deprecated" flag in dhcp-range.
1756 lease_time - configured time for context for individual client.
1757 *min_time - smallest valid time sent so far.
1758
1759 Outputs are :
1760
1761 *valid_timep, *preferred_timep - times to be send in IAADDR option.
1762 *min_time - smallest valid time sent so far, to calculate T1 and T2.
1763
1764 */
Simon Kelleyde92b472013-03-15 18:25:10 +00001765static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001766 unsigned int *preferred_timep, unsigned int lease_time)
Simon Kelleyde92b472013-03-15 18:25:10 +00001767{
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001768 unsigned int req_preferred = *preferred_timep, req_valid = *valid_timep;
1769 unsigned int valid_time = lease_time, preferred_time = lease_time;
1770
1771 /* RFC 3315: "A server ignores the lifetimes set
1772 by the client if the preferred lifetime is greater than the valid
1773 lifetime. */
1774 if (req_preferred <= req_valid)
1775 {
1776 if (req_preferred != 0)
1777 {
1778 /* 0 == "no preference from client" */
1779 if (req_preferred < 120u)
1780 req_preferred = 120u; /* sanity */
1781
1782 if (req_preferred < preferred_time)
1783 preferred_time = req_preferred;
1784 }
1785
1786 if (req_valid != 0)
1787 /* 0 == "no preference from client" */
1788 {
1789 if (req_valid < 120u)
1790 req_valid = 120u; /* sanity */
1791
1792 if (req_valid < valid_time)
1793 valid_time = req_valid;
1794 }
1795 }
Simon Kelleyde92b472013-03-15 18:25:10 +00001796
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001797 /* deprecate (preferred == 0) which configured, or when local address
1798 is deprecated */
1799 if ((context->flags & CONTEXT_DEPRECATE) || context->preferred == 0)
Simon Kelleyde92b472013-03-15 18:25:10 +00001800 preferred_time = 0;
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001801
Simon Kelleyde92b472013-03-15 18:25:10 +00001802 if (preferred_time != 0 && preferred_time < *min_time)
1803 *min_time = preferred_time;
1804
1805 if (valid_time != 0 && valid_time < *min_time)
1806 *min_time = valid_time;
1807
1808 *valid_timep = valid_time;
1809 *preferred_timep = preferred_time;
1810}
1811
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001812static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now)
1813{
1814 struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0);
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001815#ifdef HAVE_SCRIPT
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001816 struct dhcp_netid *tagif = run_tag_if(state->tags);
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001817#endif
1818
1819 (void)context;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001820
1821 if (!lease)
1822 lease = lease6_allocate(addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
1823
1824 if (lease)
1825 {
1826 lease_set_expires(lease, lease_time, now);
Simon Kelley89500e32013-09-20 16:29:20 +01001827 lease_set_iaid(lease, state->iaid);
1828 lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001829 lease_set_interface(lease, state->interface, now);
1830 if (state->hostname && state->ia_type == OPTION6_IA_NA)
1831 {
1832 char *addr_domain = get_domain6(addr);
1833 if (!state->send_domain)
1834 state->send_domain = addr_domain;
1835 lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
1836 }
1837
1838#ifdef HAVE_SCRIPT
1839 if (daemon->lease_change_command)
1840 {
1841 void *class_opt;
1842 lease->flags |= LEASE_CHANGED;
1843 free(lease->extradata);
1844 lease->extradata = NULL;
1845 lease->extradata_size = lease->extradata_len = 0;
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001846 lease->vendorclass_count = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001847
1848 if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
1849 {
1850 void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001851 lease->vendorclass_count++;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001852 /* send enterprise number first */
1853 sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4));
1854 lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
1855
1856 if (opt6_len(class_opt) >= 6)
1857 for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1858 {
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001859 lease->vendorclass_count++;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001860 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1861 }
1862 }
1863
1864 lease_add_extradata(lease, (unsigned char *)state->client_hostname,
1865 state->client_hostname ? strlen(state->client_hostname) : 0, 0);
1866
1867 /* space-concat tag set */
1868 if (!tagif && !context->netid.net)
1869 lease_add_extradata(lease, NULL, 0, 0);
1870 else
1871 {
1872 if (context->netid.net)
1873 lease_add_extradata(lease, (unsigned char *)context->netid.net, strlen(context->netid.net), tagif ? ' ' : 0);
1874
1875 if (tagif)
1876 {
1877 struct dhcp_netid *n;
1878 for (n = tagif; n; n = n->next)
1879 {
1880 struct dhcp_netid *n1;
1881 /* kill dupes */
1882 for (n1 = n->next; n1; n1 = n1->next)
1883 if (strcmp(n->net, n1->net) == 0)
1884 break;
1885 if (!n1)
1886 lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
1887 }
1888 }
1889 }
1890
1891 if (state->link_address)
1892 inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
1893
1894 lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);
1895
1896 if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
1897 {
1898 void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
1899 for (enc_opt = opt6_ptr(class_opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1900 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1901 }
1902 }
1903#endif
1904
1905 }
1906}
1907
1908
1909
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001910static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts)
1911{
1912 void *opt;
1913 char *desc = nest ? "nest" : "sent";
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001914
Simon Kelleyd81b42d2013-09-23 12:26:34 +01001915 if (!option_bool(OPT_LOG_OPTS) || start_opts == end_opts)
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001916 return;
1917
1918 for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
1919 {
1920 int type = opt6_type(opt);
1921 void *ia_options = NULL;
1922 char *optname;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001923
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001924 if (type == OPTION6_IA_NA)
1925 {
1926 sprintf(daemon->namebuff, "IAID=%u T1=%u T2=%u",
1927 opt6_uint(opt, 0, 4), opt6_uint(opt, 4, 4), opt6_uint(opt, 8, 4));
1928 optname = "ia-na";
1929 ia_options = opt6_ptr(opt, 12);
1930 }
1931 else if (type == OPTION6_IA_TA)
1932 {
1933 sprintf(daemon->namebuff, "IAID=%u", opt6_uint(opt, 0, 4));
1934 optname = "ia-ta";
1935 ia_options = opt6_ptr(opt, 4);
1936 }
1937 else if (type == OPTION6_IAADDR)
1938 {
1939 inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN);
1940 sprintf(daemon->namebuff, "%s PL=%u VL=%u",
1941 daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
1942 optname = "iaaddr";
1943 ia_options = opt6_ptr(opt, 24);
1944 }
Simon Kelleyc6309242013-03-07 20:59:28 +00001945#ifdef OPTION6_PREFIX_CLASS
1946 else if (type == OPTION6_PREFIX_CLASS)
1947 {
1948 optname = "prefix-class";
1949 sprintf(daemon->namebuff, "class=%u", opt6_uint(opt, 0, 2));
1950 }
1951#endif
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001952 else if (type == OPTION6_STATUS_CODE)
1953 {
1954 int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
1955 memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
1956 daemon->namebuff[len + opt6_len(opt) - 2] = 0;
1957 optname = "status";
1958 }
1959 else
1960 {
1961 /* account for flag byte on FQDN */
1962 int offset = type == OPTION6_FQDN ? 1 : 0;
1963 optname = option_string(AF_INET6, type, opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
1964 }
1965
1966 my_syslog(MS_DHCP | LOG_INFO, "%u %s size:%3d option:%3d %s %s",
1967 xid, desc, opt6_len(opt), type, optname, daemon->namebuff);
1968
1969 if (ia_options)
1970 log6_opts(1, xid, ia_options, opt6_ptr(opt, opt6_len(opt)));
1971 }
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001972}
1973
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001974static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string)
1975{
1976 if (option_bool(OPT_LOG_OPTS) || !option_bool(OPT_QUIET_DHCP6))
1977 log6_packet(state, type, addr, string);
1978}
1979
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001980static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001981{
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001982 int clid_len = state->clid_len;
1983
Simon Kelley4cb1b322012-02-06 14:30:41 +00001984 /* avoid buffer overflow */
1985 if (clid_len > 100)
1986 clid_len = 100;
1987
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001988 print_mac(daemon->namebuff, state->clid, clid_len);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001989
1990 if (addr)
1991 {
Simon Kelleybf4e62c2016-07-22 21:37:59 +01001992 inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, DHCP_BUFF_SZ - 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001993 strcat(daemon->dhcp_buff2, " ");
1994 }
1995 else
1996 daemon->dhcp_buff2[0] = 0;
1997
1998 if(option_bool(OPT_LOG_OPTS))
Simon Kelley58dc02e2012-02-27 11:49:37 +00001999 my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s %s",
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002000 state->xid,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002001 type,
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002002 state->iface_name,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002003 daemon->dhcp_buff2,
Simon Kelley58dc02e2012-02-27 11:49:37 +00002004 daemon->namebuff,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002005 string ? string : "");
2006 else
Simon Kelley58dc02e2012-02-27 11:49:37 +00002007 my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s %s",
Simon Kelley4cb1b322012-02-06 14:30:41 +00002008 type,
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002009 state->iface_name,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002010 daemon->dhcp_buff2,
Simon Kelley58dc02e2012-02-27 11:49:37 +00002011 daemon->namebuff,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002012 string ? string : "");
2013}
2014
2015static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
Simon Kelleyc72daea2012-01-05 21:33:27 +00002016{
2017 u16 opt, opt_len;
2018 void *start;
2019
2020 if (!opts)
2021 return NULL;
2022
2023 while (1)
2024 {
2025 if (end - opts < 4)
2026 return NULL;
2027
2028 start = opts;
2029 GETSHORT(opt, opts);
2030 GETSHORT(opt_len, opts);
2031
2032 if (opt_len > (end - opts))
2033 return NULL;
2034
2035 if (opt == search && (opt_len >= minsize))
2036 return start;
2037
2038 opts += opt_len;
2039 }
2040}
2041
Simon Kelley4cb1b322012-02-06 14:30:41 +00002042static void *opt6_next(void *opts, void *end)
Simon Kelleyc72daea2012-01-05 21:33:27 +00002043{
2044 u16 opt_len;
2045
2046 if (end - opts < 4)
2047 return NULL;
2048
2049 opts += 2;
2050 GETSHORT(opt_len, opts);
2051
2052 if (opt_len >= (end - opts))
2053 return NULL;
2054
2055 return opts + opt_len;
2056}
Simon Kelleyc72daea2012-01-05 21:33:27 +00002057
2058static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
2059{
2060 /* this worries about unaligned data and byte order */
2061 unsigned int ret = 0;
2062 int i;
2063 unsigned char *p = opt6_ptr(opt, offset);
2064
2065 for (i = 0; i < size; i++)
2066 ret = (ret << 8) | *p++;
2067
2068 return ret;
Simon Kelley4cb1b322012-02-06 14:30:41 +00002069}
Simon Kelleyc72daea2012-01-05 21:33:27 +00002070
Simon Kelley33702ab2015-12-28 23:17:15 +00002071void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
2072 struct in6_addr *peer_address, u32 scope_id, time_t now)
Simon Kelleyff7eea22013-09-04 18:01:38 +01002073{
2074 /* ->local is same value for all relays on ->current chain */
2075
2076 struct all_addr from;
2077 unsigned char *header;
2078 unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2079 int msg_type = *inbuff;
2080 int hopcount;
2081 struct in6_addr multicast;
Simon Kelley8939c952013-09-25 11:49:34 +01002082 unsigned int maclen, mactype;
2083 unsigned char mac[DHCP_CHADDR_MAX];
Simon Kelleyff7eea22013-09-04 18:01:38 +01002084
2085 inet_pton(AF_INET6, ALL_SERVERS, &multicast);
Simon Kelley33702ab2015-12-28 23:17:15 +00002086 get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
Simon Kelley8939c952013-09-25 11:49:34 +01002087
Simon Kelleyff7eea22013-09-04 18:01:38 +01002088 /* source address == relay address */
2089 from.addr.addr6 = relay->local.addr.addr6;
2090
2091 /* Get hop count from nested relayed message */
2092 if (msg_type == DHCP6RELAYFORW)
2093 hopcount = *((unsigned char *)inbuff+1) + 1;
2094 else
2095 hopcount = 0;
2096
2097 /* RFC 3315 HOP_COUNT_LIMIT */
2098 if (hopcount > 32)
2099 return;
2100
Simon Kelleyfa785732016-07-22 20:56:01 +01002101 reset_counter();
Simon Kelleyff7eea22013-09-04 18:01:38 +01002102
2103 if ((header = put_opt6(NULL, 34)))
2104 {
2105 int o;
2106
2107 header[0] = DHCP6RELAYFORW;
2108 header[1] = hopcount;
2109 memcpy(&header[2], &relay->local.addr.addr6, IN6ADDRSZ);
2110 memcpy(&header[18], peer_address, IN6ADDRSZ);
Simon Kelley89500e32013-09-20 16:29:20 +01002111
2112 /* RFC-6939 */
Simon Kelley8939c952013-09-25 11:49:34 +01002113 if (maclen != 0)
Simon Kelley89500e32013-09-20 16:29:20 +01002114 {
2115 o = new_opt6(OPTION6_CLIENT_MAC);
Simon Kelley8939c952013-09-25 11:49:34 +01002116 put_opt6_short(mactype);
2117 put_opt6(mac, maclen);
Simon Kelley89500e32013-09-20 16:29:20 +01002118 end_opt6(o);
2119 }
Simon Kelleyff7eea22013-09-04 18:01:38 +01002120
2121 o = new_opt6(OPTION6_RELAY_MSG);
2122 put_opt6(inbuff, sz);
2123 end_opt6(o);
2124
2125 for (; relay; relay = relay->current)
2126 {
2127 union mysockaddr to;
2128
2129 to.sa.sa_family = AF_INET6;
2130 to.in6.sin6_addr = relay->server.addr.addr6;
2131 to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
2132 to.in6.sin6_flowinfo = 0;
2133 to.in6.sin6_scope_id = 0;
2134
2135 if (IN6_ARE_ADDR_EQUAL(&relay->server.addr.addr6, &multicast))
2136 {
2137 int multicast_iface;
2138 if (!relay->interface || strchr(relay->interface, '*') ||
2139 (multicast_iface = if_nametoindex(relay->interface)) == 0 ||
2140 setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
2141 my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
2142 }
2143
Simon Kelley6b1c4642016-07-22 20:59:16 +01002144 send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
Simon Kelleyff7eea22013-09-04 18:01:38 +01002145
2146 if (option_bool(OPT_LOG_OPTS))
2147 {
2148 inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
2149 inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
2150 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff);
2151 }
2152
2153 /* Save this for replies */
2154 relay->iface_index = scope_id;
2155 }
2156 }
2157}
2158
2159unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
2160{
2161 struct dhcp_relay *relay;
2162 struct in6_addr link;
2163 unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2164
2165 /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
2166 which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
2167
2168 if (sz < 38 || *inbuff != DHCP6RELAYREPL)
2169 return 0;
2170
2171 memcpy(&link, &inbuff[2], IN6ADDRSZ);
2172
2173 for (relay = daemon->relay6; relay; relay = relay->next)
2174 if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr.addr6) &&
2175 (!relay->interface || wildcard_match(relay->interface, arrival_interface)))
2176 break;
2177
Simon Kelleyfa785732016-07-22 20:56:01 +01002178 reset_counter();
Simon Kelleyff7eea22013-09-04 18:01:38 +01002179
2180 if (relay)
2181 {
2182 void *opt, *opts = inbuff + 34;
2183 void *end = inbuff + sz;
2184 for (opt = opts; opt; opt = opt6_next(opt, end))
2185 if (opt6_type(opt) == OPTION6_RELAY_MSG && opt6_len(opt) > 0)
2186 {
2187 int encap_type = *((unsigned char *)opt6_ptr(opt, 0));
2188 put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
2189 memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
2190 peer->sin6_scope_id = relay->iface_index;
2191 return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
2192 }
2193 }
2194
2195 return 0;
2196}
2197
Simon Kelleyc72daea2012-01-05 21:33:27 +00002198#endif