blob: 364277d983487eeb80d8a8add9e103f0f653c650 [file] [log] [blame]
Simon Kelleyc47e3ba2014-01-08 17:07:54 +00001/* dnsmasq is Copyright (c) 2000-2014 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 Kelleyc5ad4e72012-02-24 16:06:20 +000092 save_counter(0);
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
121 /* if not an encaplsulated relayed message, just do the stuff */
122 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)
133 get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type);
134 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 Kelleyf1af2bb2013-09-24 09:16:28 +0100209 state->mac_type = opt6_uint(opt, 0, 2);
210 state->mac_len = opt6_len(opt) - 2;
Simon Kelley8939c952013-09-25 11:49:34 +0100211 memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
Simon Kelley89500e32013-09-20 16:29:20 +0100212 }
213
Simon Kelley4cb1b322012-02-06 14:30:41 +0000214 for (opt = opts; opt; opt = opt6_next(opt, end))
215 {
216 int o = new_opt6(opt6_type(opt));
217 if (opt6_type(opt) == OPTION6_RELAY_MSG)
218 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100219 struct in6_addr align;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000220 /* the packet data is unaligned, copy to aligned storage */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100221 memcpy(&align, inbuff + 2, IN6ADDRSZ);
222 state->link_address = &align;
223 /* zero is_unicast since that is now known to refer to the
Simon Kelley4cb1b322012-02-06 14:30:41 +0000224 relayed packet, not the original sent by the client */
Simon Kelley8939c952013-09-25 11:49:34 +0100225 if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000226 return 0;
227 }
Simon Kelley89500e32013-09-20 16:29:20 +0100228 else if (opt6_type(opt) != OPTION6_CLIENT_MAC)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000229 put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
230 end_opt6(o);
231 }
232
233 return 1;
234}
235
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100236static 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 +0000237{
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000238 void *opt;
239 int i, o, o1, start_opts;
240 struct dhcp_opt *opt_cfg;
241 struct dhcp_netid *tagif;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000242 struct dhcp_config *config = NULL;
Simon Kelley0d28af82012-09-20 21:24:06 +0100243 struct dhcp_netid known_id, iface_id, v6_id;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000244 unsigned char *outmsgtypep;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000245 struct dhcp_vendor *vendor;
246 struct dhcp_context *context_tmp;
Simon Kelley89500e32013-09-20 16:29:20 +0100247 struct dhcp_mac *mac_opt;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000248 unsigned int ignore = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000249#ifdef OPTION6_PREFIX_CLASS
Simon Kelley6e37ab52013-03-19 20:50:11 +0000250 struct prefix_class *p;
251 int dump_all_prefix_classes = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000252#endif
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000253
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100254 state->packet_options = inbuff + 4;
255 state->end = inbuff + sz;
256 state->clid = NULL;
257 state->clid_len = 0;
258 state->lease_allocate = 0;
259 state->context_tags = NULL;
260 state->domain = NULL;
261 state->send_domain = NULL;
262 state->hostname_auth = 0;
263 state->hostname = NULL;
264 state->client_hostname = NULL;
265 state->fqdn_flags = 0x01; /* default to send if we recieve no FQDN option */
Simon Kelleyc6309242013-03-07 20:59:28 +0000266#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100267 state->send_prefix_class = NULL;
Simon Kelleyc6309242013-03-07 20:59:28 +0000268#endif
Simon Kelley4cb1b322012-02-06 14:30:41 +0000269
Simon Kelleyceae00d2012-02-09 21:28:14 +0000270 /* set tag with name == interface */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100271 iface_id.net = state->iface_name;
272 iface_id.next = state->tags;
273 state->tags = &iface_id;
Simon Kelleyceae00d2012-02-09 21:28:14 +0000274
Simon Kelley23780dd2012-10-23 17:04:37 +0100275 /* set tag "dhcpv6" */
276 v6_id.net = "dhcpv6";
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100277 v6_id.next = state->tags;
278 state->tags = &v6_id;
Simon Kelley0d28af82012-09-20 21:24:06 +0100279
Simon Kelley4cb1b322012-02-06 14:30:41 +0000280 /* copy over transaction-id, and save pointer to message type */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100281 if (!(outmsgtypep = put_opt6(inbuff, 4)))
282 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000283 start_opts = save_counter(-1);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100284 state->xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000285
286 /* We're going to be linking tags from all context we use.
287 mark them as unused so we don't link one twice and break the list */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100288 for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000289 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100290 context_tmp->netid.next = &context_tmp->netid;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000291
292 if (option_bool(OPT_LOG_OPTS))
293 {
294 inet_ntop(AF_INET6, &context_tmp->start6, daemon->dhcp_buff, ADDRSTRLEN);
295 inet_ntop(AF_INET6, &context_tmp->end6, daemon->dhcp_buff2, ADDRSTRLEN);
296 if (context_tmp->flags & (CONTEXT_STATIC))
297 my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCPv6 subnet: %s/%d"),
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100298 state->xid, daemon->dhcp_buff, context_tmp->prefix);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000299 else
300 my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"),
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100301 state->xid, daemon->dhcp_buff, daemon->dhcp_buff2);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000302 }
303 }
304
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100305 if ((opt = opt6_find(state->packet_options, state->end, OPTION6_CLIENT_ID, 1)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000306 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100307 state->clid = opt6_ptr(opt, 0);
308 state->clid_len = opt6_len(opt);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000309 o = new_opt6(OPTION6_CLIENT_ID);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100310 put_opt6(state->clid, state->clid_len);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000311 end_opt6(o);
312 }
313 else if (msg_type != DHCP6IREQ)
314 return 0;
315
316 /* server-id must match except for SOLICIT and CONFIRM messages */
317 if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ &&
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100318 (!(opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1)) ||
Simon Kelley4cb1b322012-02-06 14:30:41 +0000319 opt6_len(opt) != daemon->duid_len ||
320 memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
321 return 0;
322
323 o = new_opt6(OPTION6_SERVER_ID);
324 put_opt6(daemon->duid, daemon->duid_len);
325 end_opt6(o);
326
327 if (is_unicast &&
328 (msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
329
330 {
331 o1 = new_opt6(OPTION6_STATUS_CODE);
332 put_opt6_short(DHCP6USEMULTI);
333 put_opt6_string("Use multicast");
334 end_opt6(o1);
335 return 1;
336 }
337
338 /* match vendor and user class options */
339 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
340 {
341 int mopt;
342
343 if (vendor->match_type == MATCH_VENDOR)
344 mopt = OPTION6_VENDOR_CLASS;
345 else if (vendor->match_type == MATCH_USER)
346 mopt = OPTION6_USER_CLASS;
347 else
348 continue;
349
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100350 if ((opt = opt6_find(state->packet_options, state->end, mopt, 2)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000351 {
352 void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt));
Simon Kelleya5c72ab2012-02-10 13:42:47 +0000353 int offset = 0;
354
355 if (mopt == OPTION6_VENDOR_CLASS)
356 {
357 if (opt6_len(opt) < 4)
358 continue;
359
360 if (vendor->enterprise != opt6_uint(opt, 0, 4))
361 continue;
362
363 offset = 4;
364 }
365
Tanguy Bouzelocef1d7422013-10-03 11:06:31 +0100366 /* Note that format if user/vendor classes is different to DHCP options - no option types. */
367 for (enc_opt = opt6_ptr(opt, offset); enc_opt; enc_opt = opt6_user_vendor_next(enc_opt, enc_end))
368 for (i = 0; i <= (opt6_user_vendor_len(enc_opt) - vendor->len); i++)
369 if (memcmp(vendor->data, opt6_user_vendor_ptr(enc_opt, i), vendor->len) == 0)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000370 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100371 vendor->netid.next = state->tags;
372 state->tags = &vendor->netid;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000373 break;
374 }
375 }
376 }
Simon Kelley3634c542012-02-08 14:22:37 +0000377
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100378 if (option_bool(OPT_LOG_OPTS) && (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
379 my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %u"), state->xid, opt6_uint(opt, 0, 4));
Simon Kelley1567fea2012-03-12 22:15:35 +0000380
Simon Kelley3634c542012-02-08 14:22:37 +0000381 /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
382 Otherwise assume the option is an array, and look for a matching element.
383 If no data given, existance of the option is enough. This code handles
384 V-I opts too. */
385 for (opt_cfg = daemon->dhcp_match6; opt_cfg; opt_cfg = opt_cfg->next)
386 {
Simon Kelleyceae00d2012-02-09 21:28:14 +0000387 int match = 0;
388
Simon Kelley3634c542012-02-08 14:22:37 +0000389 if (opt_cfg->flags & DHOPT_RFC3925)
390 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100391 for (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_OPTS, 4);
Simon Kelley3634c542012-02-08 14:22:37 +0000392 opt;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100393 opt = opt6_find(opt6_next(opt, state->end), state->end, OPTION6_VENDOR_OPTS, 4))
Simon Kelley3634c542012-02-08 14:22:37 +0000394 {
395 void *vopt;
396 void *vend = opt6_ptr(opt, opt6_len(opt));
397
398 for (vopt = opt6_find(opt6_ptr(opt, 4), vend, opt_cfg->opt, 0);
399 vopt;
400 vopt = opt6_find(opt6_next(vopt, vend), vend, opt_cfg->opt, 0))
Simon Kelleyceae00d2012-02-09 21:28:14 +0000401 if ((match = match_bytes(opt_cfg, opt6_ptr(vopt, 0), opt6_len(vopt))))
Simon Kelley3634c542012-02-08 14:22:37 +0000402 break;
403 }
404 if (match)
405 break;
406 }
407 else
408 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100409 if (!(opt = opt6_find(state->packet_options, state->end, opt_cfg->opt, 1)))
Simon Kelley3634c542012-02-08 14:22:37 +0000410 continue;
411
412 match = match_bytes(opt_cfg, opt6_ptr(opt, 0), opt6_len(opt));
413 }
414
415 if (match)
416 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100417 opt_cfg->netid->next = state->tags;
418 state->tags = opt_cfg->netid;
Simon Kelley3634c542012-02-08 14:22:37 +0000419 }
420 }
Simon Kelley89500e32013-09-20 16:29:20 +0100421
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100422 if (state->mac_len != 0)
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100423 {
424 if (option_bool(OPT_LOG_OPTS))
Simon Kelley89500e32013-09-20 16:29:20 +0100425 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100426 print_mac(daemon->dhcp_buff, state->mac, state->mac_len);
427 my_syslog(MS_DHCP | LOG_INFO, _("%u client MAC address: %s"), state->xid, daemon->dhcp_buff);
Simon Kelley89500e32013-09-20 16:29:20 +0100428 }
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100429
430 for (mac_opt = daemon->dhcp_macs; mac_opt; mac_opt = mac_opt->next)
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100431 if ((unsigned)mac_opt->hwaddr_len == state->mac_len &&
432 ((unsigned)mac_opt->hwaddr_type == state->mac_type || mac_opt->hwaddr_type == 0) &&
433 memcmp_masked(mac_opt->hwaddr, state->mac, state->mac_len, mac_opt->mask))
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100434 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100435 mac_opt->netid.next = state->tags;
436 state->tags = &mac_opt->netid;
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100437 }
438 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000439
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100440 if ((opt = opt6_find(state->packet_options, state->end, OPTION6_FQDN, 1)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000441 {
442 /* RFC4704 refers */
443 int len = opt6_len(opt) - 1;
444
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100445 state->fqdn_flags = opt6_uint(opt, 0, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000446
447 /* Always force update, since the client has no way to do it itself. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100448 if (!option_bool(OPT_FQDN_UPDATE) && !(state->fqdn_flags & 0x01))
449 state->fqdn_flags |= 0x03;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000450
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100451 state->fqdn_flags &= ~0x04;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000452
453 if (len != 0 && len < 255)
454 {
Simon Kelleyfbbc1452012-03-30 20:48:20 +0100455 unsigned char *pp, *op = opt6_ptr(opt, 1);
456 char *pq = daemon->dhcp_buff;
457
458 pp = op;
459 while (*op != 0 && ((op + (*op)) - pp) < len)
460 {
461 memcpy(pq, op+1, *op);
462 pq += *op;
463 op += (*op)+1;
464 *(pq++) = '.';
465 }
466
467 if (pq != daemon->dhcp_buff)
468 pq--;
469 *pq = 0;
470
471 if (legal_hostname(daemon->dhcp_buff))
472 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100473 state->client_hostname = daemon->dhcp_buff;
Simon Kelleyfbbc1452012-03-30 20:48:20 +0100474 if (option_bool(OPT_LOG_OPTS))
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100475 my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), state->xid, state->client_hostname);
Simon Kelleyfbbc1452012-03-30 20:48:20 +0100476 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000477 }
478 }
479
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100480 if (state->clid)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000481 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100482 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 +0000483
484 if (have_config(config, CONFIG_NAME))
485 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100486 state->hostname = config->hostname;
487 state->domain = config->domain;
488 state->hostname_auth = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000489 }
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100490 else if (state->client_hostname)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000491 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100492 state->domain = strip_hostname(state->client_hostname);
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000493
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100494 if (strlen(state->client_hostname) != 0)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000495 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100496 state->hostname = state->client_hostname;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000497 if (!config)
498 {
499 /* Search again now we have a hostname.
Simon Kelley00e9ad52012-02-16 21:53:11 +0000500 Only accept configs without CLID here, (it won't match)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000501 to avoid impersonation by name. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100502 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 +0000503 if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
504 config = new;
505 }
506 }
507 }
508 }
509
510 if (config)
511 {
512 struct dhcp_netid_list *list;
513
514 for (list = config->netid; list; list = list->next)
515 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100516 list->list->next = state->tags;
517 state->tags = list->list;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000518 }
519
520 /* set "known" tag for known hosts */
521 known_id.net = "known";
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100522 known_id.next = state->tags;
523 state->tags = &known_id;
Simon Kelley3634c542012-02-08 14:22:37 +0000524
525 if (have_config(config, CONFIG_DISABLE))
526 ignore = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000527 }
Simon Kelleyc6309242013-03-07 20:59:28 +0000528
Simon Kelleyc6309242013-03-07 20:59:28 +0000529#ifdef OPTION6_PREFIX_CLASS
Simon Kelley6e37ab52013-03-19 20:50:11 +0000530 /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
531 if (daemon->prefix_classes && (msg_type == DHCP6SOLICIT || msg_type == DHCP6REQUEST))
Simon Kelleyc6309242013-03-07 20:59:28 +0000532 {
Simon Kelley6e37ab52013-03-19 20:50:11 +0000533 void *oro;
534
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100535 if ((oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0)))
Simon Kelley6e37ab52013-03-19 20:50:11 +0000536 for (i = 0; i < opt6_len(oro) - 1; i += 2)
537 if (opt6_uint(oro, i, 2) == OPTION6_PREFIX_CLASS)
538 {
539 dump_all_prefix_classes = 1;
540 break;
541 }
542
543 if (msg_type != DHCP6SOLICIT || dump_all_prefix_classes)
544 /* Add the tags associated with prefix classes so we can use the DHCP ranges.
545 Not done for SOLICIT as we add them one-at-time. */
546 for (p = daemon->prefix_classes; p ; p = p->next)
547 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100548 p->tag.next = state->tags;
549 state->tags = &p->tag;
Simon Kelley6e37ab52013-03-19 20:50:11 +0000550 }
551 }
Simon Kelleyc6309242013-03-07 20:59:28 +0000552#endif
553
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100554 tagif = run_tag_if(state->tags);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000555
Simon Kelley3634c542012-02-08 14:22:37 +0000556 /* if all the netids in the ignore list are present, ignore this client */
557 if (daemon->dhcp_ignore)
558 {
559 struct dhcp_netid_list *id_list;
560
Simon Kelley3634c542012-02-08 14:22:37 +0000561 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
562 if (match_netid(id_list->list, tagif, 0))
563 ignore = 1;
564 }
Simon Kelley00e9ad52012-02-16 21:53:11 +0000565
566 /* if all the netids in the ignore_name list are present, ignore client-supplied name */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100567 if (!state->hostname_auth)
Simon Kelley00e9ad52012-02-16 21:53:11 +0000568 {
569 struct dhcp_netid_list *id_list;
570
571 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
572 if ((!id_list->list) || match_netid(id_list->list, tagif, 0))
573 break;
574 if (id_list)
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100575 state->hostname = NULL;
Simon Kelley00e9ad52012-02-16 21:53:11 +0000576 }
577
Simon Kelley4cb1b322012-02-06 14:30:41 +0000578
579 switch (msg_type)
580 {
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000581 default:
582 return 0;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100583
584
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000585 case DHCP6SOLICIT:
586 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000587 int address_assigned = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000588 /* tags without all prefix-class tags */
Simon Kelley8f51a292013-09-21 14:07:12 +0100589 struct dhcp_netid *solicit_tags;
Simon Kelleyde92b472013-03-15 18:25:10 +0000590 struct dhcp_context *c;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100591
592 *outmsgtypep = DHCP6ADVERTISE;
593
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100594 if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000595 {
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100596 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100597 state->lease_allocate = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000598 o = new_opt6(OPTION6_RAPID_COMMIT);
599 end_opt6(o);
600 }
Simon Kelley3634c542012-02-08 14:22:37 +0000601
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100602 log6_quiet(state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL);
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100603
604 request_no_address:
Simon Kelley8f51a292013-09-21 14:07:12 +0100605 solicit_tags = tagif;
606
Simon Kelley3634c542012-02-08 14:22:37 +0000607 if (ignore)
608 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000609
Simon Kelley52a1ae72013-03-06 22:43:26 +0000610 /* reset USED bits in leases */
611 lease6_reset();
Simon Kelleyde92b472013-03-15 18:25:10 +0000612
613 /* Can use configured address max once per prefix */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100614 for (c = state->context; c; c = c->current)
Simon Kelleyde92b472013-03-15 18:25:10 +0000615 c->flags &= ~CONTEXT_CONF_USED;
616
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100617 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000618 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000619 void *ia_option, *ia_end;
620 unsigned int min_time = 0xffffffff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000621 int t1cntr;
Simon Kelleyc6309242013-03-07 20:59:28 +0000622 int ia_counter;
623 /* set unless we're sending a particular prefix-class, when we
624 want only dhcp-ranges with the correct tags set and not those without any tags. */
625 int plain_range = 1;
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100626 u32 lease_time;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000627 struct dhcp_lease *ltmp;
628 struct in6_addr *req_addr;
629 struct in6_addr addr;
Simon Kelleyc6309242013-03-07 20:59:28 +0000630
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100631 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000632 continue;
633
Simon Kelley52a1ae72013-03-06 22:43:26 +0000634 /* reset USED bits in contexts - one address per prefix per IAID */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100635 for (c = state->context; c; c = c->current)
Simon Kelley52a1ae72013-03-06 22:43:26 +0000636 c->flags &= ~CONTEXT_USED;
Simon Kelleyc6309242013-03-07 20:59:28 +0000637
638#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100639 if (daemon->prefix_classes && state->ia_type == OPTION6_IA_NA)
Simon Kelleyc6309242013-03-07 20:59:28 +0000640 {
Simon Kelley6e37ab52013-03-19 20:50:11 +0000641 void *prefix_opt;
Simon Kelleyc6309242013-03-07 20:59:28 +0000642 int prefix_class;
643
Simon Kelley6e37ab52013-03-19 20:50:11 +0000644 if (dump_all_prefix_classes)
645 /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
646 plain_range = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000647 else
648 {
649 if ((prefix_opt = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_PREFIX_CLASS, 2)))
650 {
651
652 prefix_class = opt6_uint(prefix_opt, 0, 2);
653
654 for (p = daemon->prefix_classes; p ; p = p->next)
655 if (p->class == prefix_class)
656 break;
657
658 if (!p)
659 my_syslog(MS_DHCP | LOG_WARNING, _("unknown prefix-class %d"), prefix_class);
660 else
661 {
662 /* add tag to list, and exclude undecorated dhcp-ranges */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100663 p->tag.next = state->tags;
Simon Kelleyc6309242013-03-07 20:59:28 +0000664 solicit_tags = run_tag_if(&p->tag);
665 plain_range = 0;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100666 state->send_prefix_class = p;
Simon Kelleyc6309242013-03-07 20:59:28 +0000667 }
668 }
669 else
670 {
671 /* client didn't ask for a prefix class, lets see if we can find one. */
672 for (p = daemon->prefix_classes; p ; p = p->next)
673 {
674 p->tag.next = NULL;
675 if (match_netid(&p->tag, solicit_tags, 1))
676 break;
677 }
678
679 if (p)
680 {
681 plain_range = 0;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100682 state->send_prefix_class = p;
Simon Kelleyc6309242013-03-07 20:59:28 +0000683 }
684 }
685
686 if (p && option_bool(OPT_LOG_OPTS))
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100687 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 +0000688 }
689 }
690#endif
691
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100692 o = build_ia(state, &t1cntr);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000693
Simon Kelleyc6309242013-03-07 20:59:28 +0000694 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 +0000695 {
696 req_addr = opt6_ptr(ia_option, 0);
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100697
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100698 if ((c = address6_valid(state->context, req_addr, solicit_tags, plain_range)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000699 {
700 lease_time = c->lease_time;
701 /* If the client asks for an address on the same network as a configured address,
702 offer the configured address instead, to make moving to newly-configured
703 addresses automatic. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100704 if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000705 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000706 req_addr = &addr;
707 mark_config_used(c, &addr);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000708 if (have_config(config, CONFIG_TIME))
709 lease_time = config->lease_time;
710 }
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100711 else if (!(c = address6_available(state->context, req_addr, solicit_tags, plain_range)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000712 continue; /* not an address we're allowed */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100713 else if (!check_address(state, req_addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000714 continue; /* address leased elsewhere */
715
716 /* add address to output packet */
Simon Kelleyc6309242013-03-07 20:59:28 +0000717#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100718 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
719 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000720#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100721 add_address(state, c, lease_time, ia_option, &min_time, req_addr, now);
722 mark_context_used(state, req_addr);
723 get_context_tag(state, c);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000724 address_assigned = 1;
725 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000726 }
727
Simon Kelleyde92b472013-03-15 18:25:10 +0000728 /* Suggest configured address(es) */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100729 for (c = state->context; c; c = c->current)
Simon Kelleya1a79ed2013-03-15 21:19:57 +0000730 if (!(c->flags & CONTEXT_CONF_USED) &&
731 match_netid(c->filter, solicit_tags, plain_range) &&
732 config_valid(config, c, &addr) &&
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100733 check_address(state, &addr))
Simon Kelleyde92b472013-03-15 18:25:10 +0000734 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100735 mark_config_used(state->context, &addr);
Simon Kelleyde92b472013-03-15 18:25:10 +0000736 if (have_config(config, CONFIG_TIME))
737 lease_time = config->lease_time;
Simon Kelleya1a79ed2013-03-15 21:19:57 +0000738 else
739 lease_time = c->lease_time;
Simon Kelleyde92b472013-03-15 18:25:10 +0000740 /* add address to output packet */
Simon Kelleyc6309242013-03-07 20:59:28 +0000741#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100742 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
743 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000744#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100745 add_address(state, c, lease_time, NULL, &min_time, &addr, now);
746 mark_context_used(state, &addr);
747 get_context_tag(state, c);
Simon Kelleyde92b472013-03-15 18:25:10 +0000748 address_assigned = 1;
749 }
750
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000751 /* return addresses for existing leases */
752 ltmp = NULL;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100753 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 +0000754 {
Simon Kelley89500e32013-09-20 16:29:20 +0100755 req_addr = &ltmp->addr6;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100756 if ((c = address6_available(state->context, req_addr, solicit_tags, plain_range)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000757 {
Simon Kelleyc6309242013-03-07 20:59:28 +0000758#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100759 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
760 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000761#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100762 add_address(state, c, c->lease_time, NULL, &min_time, req_addr, now);
763 mark_context_used(state, req_addr);
764 get_context_tag(state, c);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000765 address_assigned = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000766 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000767 }
768
769 /* Return addresses for all valid contexts which don't yet have one */
Simon Kelley6586e832013-11-07 14:20:13 +0000770 while ((c = address6_allocate(state->context, state->clid, state->clid_len, state->ia_type == OPTION6_IA_TA,
771 state->iaid, ia_counter, solicit_tags, plain_range, &addr)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000772 {
Simon Kelleyc6309242013-03-07 20:59:28 +0000773#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100774 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
775 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000776#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100777 add_address(state, c, c->lease_time, NULL, &min_time, &addr, now);
778 mark_context_used(state, &addr);
779 get_context_tag(state, c);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000780 address_assigned = 1;
781 }
782
783 end_ia(t1cntr, min_time, 0);
784 end_opt6(o);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000785 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000786
787 if (address_assigned)
788 {
789 o1 = new_opt6(OPTION6_STATUS_CODE);
790 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000791 put_opt6_string(_("success"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000792 end_opt6(o1);
793
794 /* If --dhcp-authoritative is set, we can tell client not to wait for
795 other possible servers */
796 o = new_opt6(OPTION6_PREFERENCE);
797 put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0);
798 end_opt6(o);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100799 tagif = add_options(state, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000800 }
801 else
802 {
803 /* no address, return error */
804 o1 = new_opt6(OPTION6_STATUS_CODE);
805 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000806 put_opt6_string(_("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000807 end_opt6(o1);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100808 log6_packet(state, "DHCPADVERTISE", NULL, _("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000809 }
810
Simon Kelley4cb1b322012-02-06 14:30:41 +0000811 break;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000812 }
813
814 case DHCP6REQUEST:
815 {
816 int address_assigned = 0;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100817 int start = save_counter(-1);
818
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000819 /* set reply message type */
820 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100821 state->lease_allocate = 1;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000822
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100823 log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000824
825 if (ignore)
826 return 0;
827
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100828 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000829 {
830 void *ia_option, *ia_end;
831 unsigned int min_time = 0xffffffff;
832 int t1cntr;
833
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100834 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley3a654c52013-03-06 22:17:48 +0000835 continue;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100836
837 if (!ia_option)
838 {
839 /* If we get a request with a IA_*A without addresses, treat it exactly like
840 a SOLICT with rapid commit set. */
841 save_counter(start);
842 goto request_no_address;
843 }
844
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100845 o = build_ia(state, &t1cntr);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000846
847 for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
848 {
849 struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000850 struct dhcp_context *dynamic, *c;
851 unsigned int lease_time;
Simon Kelleyde92b472013-03-15 18:25:10 +0000852 struct in6_addr addr;
853 int config_ok = 0;
854
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100855 if ((c = address6_valid(state->context, req_addr, tagif, 1)))
Simon Kelleyde92b472013-03-15 18:25:10 +0000856 config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr);
857
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100858 if ((dynamic = address6_available(state->context, req_addr, tagif, 1)) || c)
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000859 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000860 if (!dynamic && !config_ok)
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000861 {
862 /* Static range, not configured. */
863 o1 = new_opt6(OPTION6_STATUS_CODE);
864 put_opt6_short(DHCP6UNSPEC);
Simon Kelleyde92b472013-03-15 18:25:10 +0000865 put_opt6_string(_("address unavailable"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000866 end_opt6(o1);
867 }
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100868 else if (!check_address(state, req_addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000869 {
870 /* Address leased to another DUID/IAID */
871 o1 = new_opt6(OPTION6_STATUS_CODE);
872 put_opt6_short(DHCP6UNSPEC);
Simon Kelleyde92b472013-03-15 18:25:10 +0000873 put_opt6_string(_("address in use"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000874 end_opt6(o1);
875 }
876 else
877 {
878 if (!dynamic)
879 dynamic = c;
880
881 lease_time = dynamic->lease_time;
882
Simon Kelleyde92b472013-03-15 18:25:10 +0000883 if (config_ok && have_config(config, CONFIG_TIME))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000884 lease_time = config->lease_time;
885
Simon Kelley6e37ab52013-03-19 20:50:11 +0000886#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100887 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
888 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelley6e37ab52013-03-19 20:50:11 +0000889#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100890 add_address(state, dynamic, lease_time, ia_option, &min_time, req_addr, now);
891 get_context_tag(state, dynamic);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000892 address_assigned = 1;
893 }
894 }
Simon Kelleyde92b472013-03-15 18:25:10 +0000895 else
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000896 {
897 /* requested address not on the correct link */
898 o1 = new_opt6(OPTION6_STATUS_CODE);
899 put_opt6_short(DHCP6NOTONLINK);
Simon Kelleyde92b472013-03-15 18:25:10 +0000900 put_opt6_string(_("not on link"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000901 end_opt6(o1);
902 }
903 }
904
905 end_ia(t1cntr, min_time, 0);
906 end_opt6(o);
907 }
908
909 if (address_assigned)
910 {
911 o1 = new_opt6(OPTION6_STATUS_CODE);
912 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000913 put_opt6_string(_("success"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000914 end_opt6(o1);
915 }
916 else
917 {
918 /* no address, return error */
919 o1 = new_opt6(OPTION6_STATUS_CODE);
920 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000921 put_opt6_string(_("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000922 end_opt6(o1);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100923 log6_packet(state, "DHCPREPLY", NULL, _("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000924 }
925
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100926 tagif = add_options(state, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000927 break;
928 }
929
930
Simon Kelley4cb1b322012-02-06 14:30:41 +0000931 case DHCP6RENEW:
932 {
933 /* set reply message type */
934 *outmsgtypep = DHCP6REPLY;
935
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100936 log6_quiet(state, "DHCPRENEW", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000937
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100938 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000939 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000940 void *ia_option, *ia_end;
941 unsigned int min_time = 0xffffffff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000942 int t1cntr, iacntr;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000943
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100944 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000945 continue;
946
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100947 o = build_ia(state, &t1cntr);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000948 iacntr = save_counter(-1);
949
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000950 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 +0000951 {
952 struct dhcp_lease *lease = NULL;
953 struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100954 unsigned int preferred_time = opt6_uint(ia_option, 16, 4);
955 unsigned int valid_time = opt6_uint(ia_option, 20, 4);
Simon Kelleyde92b472013-03-15 18:25:10 +0000956 char *message = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000957 struct dhcp_context *this_context;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000958
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100959 if (!(lease = lease6_find(state->clid, state->clid_len,
960 state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
961 state->iaid, req_addr)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000962 {
963 /* If the server cannot find a client entry for the IA the server
964 returns the IA containing no addresses with a Status Code option set
965 to NoBinding in the Reply message. */
966 save_counter(iacntr);
967 t1cntr = 0;
968
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100969 log6_packet(state, "DHCPREPLY", req_addr, _("lease not found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +0000970
971 o1 = new_opt6(OPTION6_STATUS_CODE);
972 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +0000973 put_opt6_string(_("no binding found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +0000974 end_opt6(o1);
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100975
976 preferred_time = valid_time = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000977 break;
978 }
979
Simon Kelley00e9ad52012-02-16 21:53:11 +0000980
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100981 if ((this_context = address6_available(state->context, req_addr, tagif, 1)) ||
982 (this_context = address6_valid(state->context, req_addr, tagif, 1)))
Simon Kelleyc8257542012-03-28 21:15:41 +0100983 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000984 struct in6_addr addr;
985 unsigned int lease_time;
986
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100987 get_context_tag(state, this_context);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000988
Simon Kelleyde92b472013-03-15 18:25:10 +0000989 if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))
990 lease_time = config->lease_time;
991 else
992 lease_time = this_context->lease_time;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000993
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100994 calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000995
Simon Kelleyde92b472013-03-15 18:25:10 +0000996 lease_set_expires(lease, valid_time, now);
Simon Kelley89500e32013-09-20 16:29:20 +0100997 /* Update MAC record in case it's new information. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100998 if (state->mac_len != 0)
999 lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
1000 if (state->ia_type == OPTION6_IA_NA && state->hostname)
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001001 {
1002 char *addr_domain = get_domain6(req_addr);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001003 if (!state->send_domain)
1004 state->send_domain = addr_domain;
1005 lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
1006 message = state->hostname;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001007 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001008
Simon Kelleyde92b472013-03-15 18:25:10 +00001009
1010 if (preferred_time == 0)
1011 message = _("deprecated");
Simon Kelley4cb1b322012-02-06 14:30:41 +00001012 }
Simon Kelleyde92b472013-03-15 18:25:10 +00001013 else
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001014 {
1015 preferred_time = valid_time = 0;
1016 message = _("address invalid");
1017 }
1018
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001019 if (message)
1020 log6_packet(state, "DHCPREPLY", req_addr, message);
1021 else
1022 log6_quiet(state, "DHCPREPLY", req_addr, message);
1023
Simon Kelley4cb1b322012-02-06 14:30:41 +00001024 o1 = new_opt6(OPTION6_IAADDR);
1025 put_opt6(req_addr, sizeof(*req_addr));
Simon Kelleyde92b472013-03-15 18:25:10 +00001026 put_opt6_long(preferred_time);
1027 put_opt6_long(valid_time);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001028 end_opt6(o1);
1029 }
1030
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001031 end_ia(t1cntr, min_time, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001032 end_opt6(o);
1033 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001034
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001035 tagif = add_options(state, 0);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001036 break;
1037
1038 }
1039
1040 case DHCP6CONFIRM:
1041 {
1042 /* set reply message type */
1043 *outmsgtypep = DHCP6REPLY;
1044
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001045 log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001046
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001047 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001048 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001049 void *ia_option, *ia_end;
1050
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001051 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001052 ia_option;
1053 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
1054 {
1055 struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
1056
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001057 if (!address6_available(state->context, req_addr, tagif, 1))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001058 {
1059 o1 = new_opt6(OPTION6_STATUS_CODE);
1060 put_opt6_short(DHCP6NOTONLINK);
Simon Kelleyde92b472013-03-15 18:25:10 +00001061 put_opt6_string(_("confirm failed"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001062 end_opt6(o1);
1063 return 1;
1064 }
1065
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001066 log6_quiet(state, "DHCPREPLY", req_addr, state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001067 }
1068 }
1069
1070 o1 = new_opt6(OPTION6_STATUS_CODE);
1071 put_opt6_short(DHCP6SUCCESS );
Simon Kelleyde92b472013-03-15 18:25:10 +00001072 put_opt6_string(_("all addresses still on link"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001073 end_opt6(o1);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001074 break;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001075 }
1076
1077 case DHCP6IREQ:
1078 {
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001079 /* We can't discriminate contexts based on address, as we don't know it.
1080 If there is only one possible context, we can use its tags */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001081 if (state->context && state->context->netid.net && !state->context->current)
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001082 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001083 state->context->netid.next = NULL;
1084 state->context_tags = &state->context->netid;
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001085 }
Simon Kelley6bd109a2013-07-27 15:11:44 +01001086
1087 /* Similarly, we can't determine domain from address, but if the FQDN is
1088 given in --dhcp-host, we can use that, and failing that we can use the
1089 unqualified configured domain, if any. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001090 if (state->hostname_auth)
1091 state->send_domain = state->domain;
Simon Kelley6bd109a2013-07-27 15:11:44 +01001092 else
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001093 state->send_domain = get_domain6(NULL);
Simon Kelley6bd109a2013-07-27 15:11:44 +01001094
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001095 log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname);
Simon Kelley3634c542012-02-08 14:22:37 +00001096 if (ignore)
1097 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001098 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001099 tagif = add_options(state, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001100 break;
1101 }
1102
1103
1104 case DHCP6RELEASE:
1105 {
1106 /* set reply message type */
1107 *outmsgtypep = DHCP6REPLY;
1108
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001109 log6_quiet(state, "DHCPRELEASE", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001110
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001111 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001112 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001113 void *ia_option, *ia_end;
1114 int made_ia = 0;
1115
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001116 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001117 ia_option;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001118 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001119 {
1120 struct dhcp_lease *lease;
1121
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001122 if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
1123 state->iaid, opt6_ptr(ia_option, 0))))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001124 lease_prune(lease, now);
1125 else
1126 {
1127 if (!made_ia)
1128 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001129 o = new_opt6(state->ia_type);
1130 put_opt6_long(state->iaid);
1131 if (state->ia_type == OPTION6_IA_NA)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001132 {
1133 put_opt6_long(0);
1134 put_opt6_long(0);
1135 }
1136 made_ia = 1;
1137 }
1138
1139 o1 = new_opt6(OPTION6_IAADDR);
1140 put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
1141 put_opt6_long(0);
1142 put_opt6_long(0);
1143 end_opt6(o1);
1144 }
1145 }
1146
1147 if (made_ia)
1148 {
1149 o1 = new_opt6(OPTION6_STATUS_CODE);
1150 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001151 put_opt6_string(_("no binding found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001152 end_opt6(o1);
1153
1154 end_opt6(o);
1155 }
1156 }
1157
1158 o1 = new_opt6(OPTION6_STATUS_CODE);
1159 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +00001160 put_opt6_string(_("release received"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001161 end_opt6(o1);
1162
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001163 break;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001164 }
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001165
1166 case DHCP6DECLINE:
1167 {
1168 /* set reply message type */
1169 *outmsgtypep = DHCP6REPLY;
1170
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001171 log6_quiet(state, "DHCPDECLINE", NULL, NULL);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001172
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001173 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001174 {
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001175 void *ia_option, *ia_end;
1176 int made_ia = 0;
1177
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001178 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001179 ia_option;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001180 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001181 {
1182 struct dhcp_lease *lease;
1183 struct in6_addr *addrp = opt6_ptr(ia_option, 0);
1184
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001185 if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, addrp))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001186 {
Simon Kelleyceae00d2012-02-09 21:28:14 +00001187 prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001188 inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN);
1189 my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
Simon Kelleyceae00d2012-02-09 21:28:14 +00001190 daemon->addrbuff, daemon->dhcp_buff3);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001191 config->flags |= CONFIG_DECLINED;
1192 config->decline_time = now;
1193 }
1194 else
1195 /* make sure this host gets a different address next time. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001196 for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
1197 context_tmp->addr_epoch++;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001198
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001199 if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
1200 state->iaid, opt6_ptr(ia_option, 0))))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001201 lease_prune(lease, now);
1202 else
1203 {
1204 if (!made_ia)
1205 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001206 o = new_opt6(state->ia_type);
1207 put_opt6_long(state->iaid);
1208 if (state->ia_type == OPTION6_IA_NA)
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001209 {
1210 put_opt6_long(0);
1211 put_opt6_long(0);
1212 }
1213 made_ia = 1;
1214 }
1215
1216 o1 = new_opt6(OPTION6_IAADDR);
1217 put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
1218 put_opt6_long(0);
1219 put_opt6_long(0);
1220 end_opt6(o1);
1221 }
1222 }
1223
1224 if (made_ia)
1225 {
1226 o1 = new_opt6(OPTION6_STATUS_CODE);
1227 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001228 put_opt6_string(_("no binding found"));
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001229 end_opt6(o1);
1230
1231 end_opt6(o);
1232 }
1233
1234 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001235 break;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001236 }
1237
Simon Kelley4cb1b322012-02-06 14:30:41 +00001238 }
1239
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001240 log_tags(tagif, state->xid);
1241 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 +00001242
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001243 return 1;
1244
1245}
1246
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001247static struct dhcp_netid *add_options(struct state *state, int do_refresh)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001248{
Simon Kelley2763d4b2013-03-06 21:24:56 +00001249 void *oro;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001250 /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001251 struct dhcp_netid *tagif = option_filter(state->tags, state->context_tags, daemon->dhcp_opts6);
1252 struct dhcp_opt *opt_cfg;
Simon Kelley871d4562013-07-27 21:32:32 +01001253 int done_dns = 0, done_refresh = !do_refresh, do_encap = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001254 int i, o, o1;
1255
1256 oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001257
1258 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1259 {
1260 /* netids match and not encapsulated? */
1261 if (!(opt_cfg->flags & DHOPT_TAGOK))
1262 continue;
1263
1264 if (!(opt_cfg->flags & DHOPT_FORCE) && oro)
1265 {
1266 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1267 if (opt6_uint(oro, i, 2) == (unsigned)opt_cfg->opt)
1268 break;
1269
1270 /* option not requested */
1271 if (i >= opt6_len(oro) - 1)
1272 continue;
1273 }
1274
Simon Kelley871d4562013-07-27 21:32:32 +01001275 if (opt_cfg->opt == OPTION6_REFRESH_TIME)
1276 done_refresh = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001277
Simon Kelley4b86b652012-02-29 11:45:37 +00001278 if (opt_cfg->flags & DHOPT_ADDR6)
1279 {
Simon Kelleyc3a04082014-01-11 22:18:19 +00001280 int len, j;
1281 struct in6_addr *a;
1282
1283 if (opt_cfg->opt == OPTION6_DNS_SERVER)
1284 done_dns = 1;
1285
1286 for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0;
1287 j < opt_cfg->len; j += IN6ADDRSZ, a++)
1288 if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
1289 (IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)))
1290 len -= IN6ADDRSZ;
1291
1292 if (len != 0)
1293 {
1294
1295 o = new_opt6(opt_cfg->opt);
1296
1297 for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
1298 {
1299 if (IN6_IS_ADDR_UNSPECIFIED(a))
1300 {
1301 if (!add_local_addrs(state->context))
1302 put_opt6(state->fallback, IN6ADDRSZ);
1303 }
1304 else if (IN6_IS_ADDR_ULA_ZERO(a))
1305 {
1306 if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))
1307 put_opt6(state->ula_addr, IN6ADDRSZ);
1308 }
1309 else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
1310 {
1311 if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
1312 put_opt6(state->ll_addr, IN6ADDRSZ);
1313 }
1314 else
1315 put_opt6(a, IN6ADDRSZ);
Simon Kelley4b86b652012-02-29 11:45:37 +00001316 }
Simon Kelleyc3a04082014-01-11 22:18:19 +00001317
1318 end_opt6(o);
1319 }
Simon Kelley4b86b652012-02-29 11:45:37 +00001320 }
Simon Kelleyc3a04082014-01-11 22:18:19 +00001321 else
1322 {
1323 o = new_opt6(opt_cfg->opt);
1324 if (opt_cfg->val)
1325 put_opt6(opt_cfg->val, opt_cfg->len);
1326 end_opt6(o);
1327 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001328 }
1329
Simon Kelley871d4562013-07-27 21:32:32 +01001330 if (daemon->port == NAMESERVER_PORT && !done_dns)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001331 {
1332 o = new_opt6(OPTION6_DNS_SERVER);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001333 if (!add_local_addrs(state->context))
1334 put_opt6(state->fallback, IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001335 end_opt6(o);
1336 }
Simon Kelley871d4562013-07-27 21:32:32 +01001337
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001338 if (state->context && !done_refresh)
Simon Kelley871d4562013-07-27 21:32:32 +01001339 {
1340 struct dhcp_context *c;
1341 unsigned int lease_time = 0xffffffff;
1342
1343 /* Find the smallest lease tie of all contexts,
1344 subjext to the RFC-4242 stipulation that this must not
1345 be less than 600. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001346 for (c = state->context; c; c = c->next)
Simon Kelley871d4562013-07-27 21:32:32 +01001347 if (c->lease_time < lease_time)
1348 {
1349 if (c->lease_time < 600)
1350 lease_time = 600;
1351 else
1352 lease_time = c->lease_time;
1353 }
1354
1355 o = new_opt6(OPTION6_REFRESH_TIME);
1356 put_opt6_long(lease_time);
1357 end_opt6(o);
1358 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001359
1360 /* handle vendor-identifying vendor-encapsulated options,
1361 dhcp-option = vi-encap:13,17,....... */
1362 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1363 opt_cfg->flags &= ~DHOPT_ENCAP_DONE;
Simon Kelley4b86b652012-02-29 11:45:37 +00001364
Simon Kelley4cb1b322012-02-06 14:30:41 +00001365 if (oro)
1366 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1367 if (opt6_uint(oro, i, 2) == OPTION6_VENDOR_OPTS)
1368 do_encap = 1;
1369
1370 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1371 {
1372 if (opt_cfg->flags & DHOPT_RFC3925)
1373 {
1374 int found = 0;
1375 struct dhcp_opt *oc;
1376
1377 if (opt_cfg->flags & DHOPT_ENCAP_DONE)
1378 continue;
1379
1380 for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1381 {
1382 oc->flags &= ~DHOPT_ENCAP_MATCH;
1383
1384 if (!(oc->flags & DHOPT_RFC3925) || opt_cfg->u.encap != oc->u.encap)
1385 continue;
1386
1387 oc->flags |= DHOPT_ENCAP_DONE;
1388 if (match_netid(oc->netid, tagif, 1))
1389 {
1390 /* option requested/forced? */
1391 if (!oro || do_encap || (oc->flags & DHOPT_FORCE))
1392 {
1393 oc->flags |= DHOPT_ENCAP_MATCH;
1394 found = 1;
1395 }
1396 }
1397 }
1398
1399 if (found)
1400 {
1401 o = new_opt6(OPTION6_VENDOR_OPTS);
1402 put_opt6_long(opt_cfg->u.encap);
1403
1404 for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1405 if (oc->flags & DHOPT_ENCAP_MATCH)
1406 {
1407 o1 = new_opt6(oc->opt);
1408 put_opt6(oc->val, oc->len);
1409 end_opt6(o1);
1410 }
1411 end_opt6(o);
1412 }
1413 }
1414 }
Simon Kelley07933802012-02-14 20:55:25 +00001415
1416
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001417 if (state->hostname)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001418 {
1419 unsigned char *p;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001420 size_t len = strlen(state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001421
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001422 if (state->send_domain)
Roy Marples3f3adae2013-07-25 16:22:46 +01001423 len += strlen(state->send_domain) + 2;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001424
1425 o = new_opt6(OPTION6_FQDN);
Roy Marples3f3adae2013-07-25 16:22:46 +01001426 if ((p = expand(len + 2)))
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001427 {
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001428 *(p++) = state->fqdn_flags;
1429 p = do_rfc1035_name(p, state->hostname);
1430 if (state->send_domain)
Roy Marples3f3adae2013-07-25 16:22:46 +01001431 {
1432 p = do_rfc1035_name(p, state->send_domain);
1433 *p = 0;
1434 }
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001435 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001436 end_opt6(o);
1437 }
1438
1439
1440 /* logging */
1441 if (option_bool(OPT_LOG_OPTS) && oro)
1442 {
1443 char *q = daemon->namebuff;
1444 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1445 {
1446 char *s = option_string(AF_INET6, opt6_uint(oro, i, 2), NULL, 0, NULL, 0);
1447 q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
1448 "%d%s%s%s",
1449 opt6_uint(oro, i, 2),
1450 strlen(s) != 0 ? ":" : "",
1451 s,
1452 (i > opt6_len(oro) - 3) ? "" : ", ");
1453 if ( i > opt6_len(oro) - 3 || (q - daemon->namebuff) > 40)
1454 {
1455 q = daemon->namebuff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001456 my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), state->xid, daemon->namebuff);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001457 }
1458 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001459 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001460
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001461 return tagif;
1462}
1463
1464static int add_local_addrs(struct dhcp_context *context)
1465{
1466 int done = 0;
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001467
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001468 for (; context; context = context->current)
1469 if ((context->flags & CONTEXT_USED) && !IN6_IS_ADDR_UNSPECIFIED(&context->local6))
1470 {
1471 /* squash duplicates */
1472 struct dhcp_context *c;
1473 for (c = context->current; c; c = c->current)
1474 if ((c->flags & CONTEXT_USED) &&
1475 IN6_ARE_ADDR_EQUAL(&context->local6, &c->local6))
1476 break;
1477
1478 if (!c)
1479 {
1480 done = 1;
1481 put_opt6(&context->local6, IN6ADDRSZ);
1482 }
1483 }
1484
1485 return done;
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001486}
1487
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001488
1489static void get_context_tag(struct state *state, struct dhcp_context *context)
1490{
1491 /* get tags from context if we've not used it before */
1492 if (context->netid.next == &context->netid && context->netid.net)
1493 {
1494 context->netid.next = state->context_tags;
1495 state->context_tags = &context->netid;
1496 if (!state->hostname_auth)
1497 {
1498 struct dhcp_netid_list *id_list;
1499
1500 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1501 if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1502 break;
1503 if (id_list)
1504 state->hostname = NULL;
1505 }
1506 }
1507}
Simon Kelleyc6309242013-03-07 20:59:28 +00001508
1509#ifdef OPTION6_PREFIX_CLASS
1510static struct prefix_class *prefix_class_from_context(struct dhcp_context *context)
1511{
1512 struct prefix_class *p;
1513 struct dhcp_netid *t;
1514
1515 for (p = daemon->prefix_classes; p ; p = p->next)
1516 for (t = context->filter; t; t = t->next)
1517 if (strcmp(p->tag.net, t->net) == 0)
1518 return p;
1519
1520 return NULL;
1521}
1522#endif
1523
Simon Kelley3a654c52013-03-06 22:17:48 +00001524static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001525{
1526 state->ia_type = opt6_type(opt);
Simon Kelley3a654c52013-03-06 22:17:48 +00001527 *ia_option = NULL;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001528
1529 if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
Simon Kelley3a654c52013-03-06 22:17:48 +00001530 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001531
1532 if (state->ia_type == OPTION6_IA_NA && opt6_len(opt) < 12)
Simon Kelley3a654c52013-03-06 22:17:48 +00001533 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001534
1535 if (state->ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
Simon Kelley3a654c52013-03-06 22:17:48 +00001536 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001537
1538 *endp = opt6_ptr(opt, opt6_len(opt));
1539 state->iaid = opt6_uint(opt, 0, 4);
Simon Kelley3a654c52013-03-06 22:17:48 +00001540 *ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
1541
1542 return 1;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001543}
1544
1545
1546static int build_ia(struct state *state, int *t1cntr)
1547{
1548 int o = new_opt6(state->ia_type);
1549
1550 put_opt6_long(state->iaid);
1551 *t1cntr = 0;
1552
1553 if (state->ia_type == OPTION6_IA_NA)
1554 {
1555 /* save pointer */
1556 *t1cntr = save_counter(-1);
1557 /* so we can fill these in later */
1558 put_opt6_long(0);
1559 put_opt6_long(0);
1560 }
1561
1562 return o;
1563}
1564
1565static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
1566{
1567 if (t1cntr != 0)
1568 {
1569 /* go back an fill in fields in IA_NA option */
1570 int sav = save_counter(t1cntr);
1571 unsigned int t1, t2, fuzz = 0;
1572
1573 if (do_fuzz)
1574 {
1575 fuzz = rand16();
1576
1577 while (fuzz > (min_time/16))
1578 fuzz = fuzz/2;
1579 }
1580
1581 t1 = (min_time == 0xffffffff) ? 0xffffffff : min_time/2 - fuzz;
1582 t2 = (min_time == 0xffffffff) ? 0xffffffff : ((min_time/8)*7) - fuzz;
1583 put_opt6_long(t1);
1584 put_opt6_long(t2);
1585 save_counter(sav);
1586 }
1587}
1588
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001589static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
Simon Kelleyc8f2dd82013-09-13 11:22:55 +01001590 unsigned int *min_time, struct in6_addr *addr, time_t now)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001591{
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001592 unsigned int valid_time = 0, preferred_time = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001593 int o = new_opt6(OPTION6_IAADDR);
1594 struct dhcp_lease *lease;
1595
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001596 /* get client requested times */
1597 if (ia_option)
1598 {
1599 preferred_time = opt6_uint(ia_option, 16, 4);
1600 valid_time = opt6_uint(ia_option, 20, 4);
1601 }
1602
1603 calculate_times(context, min_time, &valid_time, &preferred_time, lease_time);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001604
Simon Kelleyde92b472013-03-15 18:25:10 +00001605 put_opt6(addr, sizeof(*addr));
1606 put_opt6_long(preferred_time);
1607 put_opt6_long(valid_time);
1608
Simon Kelleyc6309242013-03-07 20:59:28 +00001609#ifdef OPTION6_PREFIX_CLASS
1610 if (state->send_prefix_class)
1611 {
1612 int o1 = new_opt6(OPTION6_PREFIX_CLASS);
1613 put_opt6_short(state->send_prefix_class->class);
1614 end_opt6(o1);
1615 }
1616#endif
1617
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001618 end_opt6(o);
1619
Simon Kelleyc8f2dd82013-09-13 11:22:55 +01001620 if (state->lease_allocate)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001621 update_leases(state, context, addr, valid_time, now);
1622
1623 if ((lease = lease6_find_by_addr(addr, 128, 0)))
1624 lease->flags |= LEASE_USED;
1625
1626 /* get tags from context if we've not used it before */
1627 if (context->netid.next == &context->netid && context->netid.net)
1628 {
1629 context->netid.next = state->context_tags;
1630 state->context_tags = &context->netid;
1631
1632 if (!state->hostname_auth)
1633 {
1634 struct dhcp_netid_list *id_list;
1635
1636 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1637 if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1638 break;
1639 if (id_list)
1640 state->hostname = NULL;
1641 }
1642 }
1643
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001644 log6_quiet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001645
1646}
Simon Kelleyff59fc82013-03-07 11:00:26 +00001647
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001648static void mark_context_used(struct state *state, struct in6_addr *addr)
Simon Kelleyff59fc82013-03-07 11:00:26 +00001649{
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001650 struct dhcp_context *context;
1651
Simon Kelleyff59fc82013-03-07 11:00:26 +00001652 /* Mark that we have an address for this prefix. */
Simon Kelleyc6309242013-03-07 20:59:28 +00001653#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001654 for (context = state->context; context; context = context->current)
Simon Kelleyc6309242013-03-07 20:59:28 +00001655 if (is_same_net6(addr, &context->start6, context->prefix) &&
1656 (!state->send_prefix_class || state->send_prefix_class == prefix_class_from_context(context)))
1657 context->flags |= CONTEXT_USED;
1658#else
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001659 for (context = state->context; context; context = context->current)
Simon Kelleyff59fc82013-03-07 11:00:26 +00001660 if (is_same_net6(addr, &context->start6, context->prefix))
1661 context->flags |= CONTEXT_USED;
Simon Kelleyc6309242013-03-07 20:59:28 +00001662#endif
Simon Kelleyff59fc82013-03-07 11:00:26 +00001663}
Simon Kelleyc6309242013-03-07 20:59:28 +00001664
Simon Kelleyde92b472013-03-15 18:25:10 +00001665static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)
1666{
1667 for (; context; context = context->current)
1668 if (is_same_net6(addr, &context->start6, context->prefix))
1669 context->flags |= CONTEXT_CONF_USED;
1670}
1671
1672/* make sure address not leased to another CLID/IAID */
1673static int check_address(struct state *state, struct in6_addr *addr)
1674{
1675 struct dhcp_lease *lease;
1676
1677 if (!(lease = lease6_find_by_addr(addr, 128, 0)))
1678 return 1;
1679
1680 if (lease->clid_len != state->clid_len ||
1681 memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
Simon Kelley89500e32013-09-20 16:29:20 +01001682 lease->iaid != state->iaid)
Simon Kelleyde92b472013-03-15 18:25:10 +00001683 return 0;
1684
1685 return 1;
1686}
1687
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001688
1689/* Calculate valid and preferred times to send in leases/renewals.
1690
1691 Inputs are:
1692
1693 *valid_timep, *preferred_timep - requested times from IAADDR options.
1694 context->valid, context->preferred - times associated with subnet address on local interface.
1695 context->flags | CONTEXT_DEPRECATE - "deprecated" flag in dhcp-range.
1696 lease_time - configured time for context for individual client.
1697 *min_time - smallest valid time sent so far.
1698
1699 Outputs are :
1700
1701 *valid_timep, *preferred_timep - times to be send in IAADDR option.
1702 *min_time - smallest valid time sent so far, to calculate T1 and T2.
1703
1704 */
Simon Kelleyde92b472013-03-15 18:25:10 +00001705static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001706 unsigned int *preferred_timep, unsigned int lease_time)
Simon Kelleyde92b472013-03-15 18:25:10 +00001707{
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001708 unsigned int req_preferred = *preferred_timep, req_valid = *valid_timep;
1709 unsigned int valid_time = lease_time, preferred_time = lease_time;
1710
1711 /* RFC 3315: "A server ignores the lifetimes set
1712 by the client if the preferred lifetime is greater than the valid
1713 lifetime. */
1714 if (req_preferred <= req_valid)
1715 {
1716 if (req_preferred != 0)
1717 {
1718 /* 0 == "no preference from client" */
1719 if (req_preferred < 120u)
1720 req_preferred = 120u; /* sanity */
1721
1722 if (req_preferred < preferred_time)
1723 preferred_time = req_preferred;
1724 }
1725
1726 if (req_valid != 0)
1727 /* 0 == "no preference from client" */
1728 {
1729 if (req_valid < 120u)
1730 req_valid = 120u; /* sanity */
1731
1732 if (req_valid < valid_time)
1733 valid_time = req_valid;
1734 }
1735 }
Simon Kelleyde92b472013-03-15 18:25:10 +00001736
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001737 /* deprecate (preferred == 0) which configured, or when local address
1738 is deprecated */
1739 if ((context->flags & CONTEXT_DEPRECATE) || context->preferred == 0)
Simon Kelleyde92b472013-03-15 18:25:10 +00001740 preferred_time = 0;
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001741
Simon Kelleyde92b472013-03-15 18:25:10 +00001742 if (preferred_time != 0 && preferred_time < *min_time)
1743 *min_time = preferred_time;
1744
1745 if (valid_time != 0 && valid_time < *min_time)
1746 *min_time = valid_time;
1747
1748 *valid_timep = valid_time;
1749 *preferred_timep = preferred_time;
1750}
1751
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001752static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now)
1753{
1754 struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0);
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001755#ifdef HAVE_SCRIPT
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001756 struct dhcp_netid *tagif = run_tag_if(state->tags);
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001757#endif
1758
1759 (void)context;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001760
1761 if (!lease)
1762 lease = lease6_allocate(addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
1763
1764 if (lease)
1765 {
1766 lease_set_expires(lease, lease_time, now);
Simon Kelley89500e32013-09-20 16:29:20 +01001767 lease_set_iaid(lease, state->iaid);
1768 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 +00001769 lease_set_interface(lease, state->interface, now);
1770 if (state->hostname && state->ia_type == OPTION6_IA_NA)
1771 {
1772 char *addr_domain = get_domain6(addr);
1773 if (!state->send_domain)
1774 state->send_domain = addr_domain;
1775 lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
1776 }
1777
1778#ifdef HAVE_SCRIPT
1779 if (daemon->lease_change_command)
1780 {
1781 void *class_opt;
1782 lease->flags |= LEASE_CHANGED;
1783 free(lease->extradata);
1784 lease->extradata = NULL;
1785 lease->extradata_size = lease->extradata_len = 0;
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001786 lease->vendorclass_count = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001787
1788 if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
1789 {
1790 void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001791 lease->vendorclass_count++;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001792 /* send enterprise number first */
1793 sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4));
1794 lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
1795
1796 if (opt6_len(class_opt) >= 6)
1797 for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1798 {
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001799 lease->vendorclass_count++;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001800 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1801 }
1802 }
1803
1804 lease_add_extradata(lease, (unsigned char *)state->client_hostname,
1805 state->client_hostname ? strlen(state->client_hostname) : 0, 0);
1806
1807 /* space-concat tag set */
1808 if (!tagif && !context->netid.net)
1809 lease_add_extradata(lease, NULL, 0, 0);
1810 else
1811 {
1812 if (context->netid.net)
1813 lease_add_extradata(lease, (unsigned char *)context->netid.net, strlen(context->netid.net), tagif ? ' ' : 0);
1814
1815 if (tagif)
1816 {
1817 struct dhcp_netid *n;
1818 for (n = tagif; n; n = n->next)
1819 {
1820 struct dhcp_netid *n1;
1821 /* kill dupes */
1822 for (n1 = n->next; n1; n1 = n1->next)
1823 if (strcmp(n->net, n1->net) == 0)
1824 break;
1825 if (!n1)
1826 lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
1827 }
1828 }
1829 }
1830
1831 if (state->link_address)
1832 inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
1833
1834 lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);
1835
1836 if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
1837 {
1838 void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
1839 for (enc_opt = opt6_ptr(class_opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1840 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1841 }
1842 }
1843#endif
1844
1845 }
1846}
1847
1848
1849
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001850static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts)
1851{
1852 void *opt;
1853 char *desc = nest ? "nest" : "sent";
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001854
Simon Kelleyd81b42d2013-09-23 12:26:34 +01001855 if (!option_bool(OPT_LOG_OPTS) || start_opts == end_opts)
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001856 return;
1857
1858 for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
1859 {
1860 int type = opt6_type(opt);
1861 void *ia_options = NULL;
1862 char *optname;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001863
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001864 if (type == OPTION6_IA_NA)
1865 {
1866 sprintf(daemon->namebuff, "IAID=%u T1=%u T2=%u",
1867 opt6_uint(opt, 0, 4), opt6_uint(opt, 4, 4), opt6_uint(opt, 8, 4));
1868 optname = "ia-na";
1869 ia_options = opt6_ptr(opt, 12);
1870 }
1871 else if (type == OPTION6_IA_TA)
1872 {
1873 sprintf(daemon->namebuff, "IAID=%u", opt6_uint(opt, 0, 4));
1874 optname = "ia-ta";
1875 ia_options = opt6_ptr(opt, 4);
1876 }
1877 else if (type == OPTION6_IAADDR)
1878 {
1879 inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN);
1880 sprintf(daemon->namebuff, "%s PL=%u VL=%u",
1881 daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
1882 optname = "iaaddr";
1883 ia_options = opt6_ptr(opt, 24);
1884 }
Simon Kelleyc6309242013-03-07 20:59:28 +00001885#ifdef OPTION6_PREFIX_CLASS
1886 else if (type == OPTION6_PREFIX_CLASS)
1887 {
1888 optname = "prefix-class";
1889 sprintf(daemon->namebuff, "class=%u", opt6_uint(opt, 0, 2));
1890 }
1891#endif
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001892 else if (type == OPTION6_STATUS_CODE)
1893 {
1894 int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
1895 memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
1896 daemon->namebuff[len + opt6_len(opt) - 2] = 0;
1897 optname = "status";
1898 }
1899 else
1900 {
1901 /* account for flag byte on FQDN */
1902 int offset = type == OPTION6_FQDN ? 1 : 0;
1903 optname = option_string(AF_INET6, type, opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
1904 }
1905
1906 my_syslog(MS_DHCP | LOG_INFO, "%u %s size:%3d option:%3d %s %s",
1907 xid, desc, opt6_len(opt), type, optname, daemon->namebuff);
1908
1909 if (ia_options)
1910 log6_opts(1, xid, ia_options, opt6_ptr(opt, opt6_len(opt)));
1911 }
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001912}
1913
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001914static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string)
1915{
1916 if (option_bool(OPT_LOG_OPTS) || !option_bool(OPT_QUIET_DHCP6))
1917 log6_packet(state, type, addr, string);
1918}
1919
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001920static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001921{
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001922 int clid_len = state->clid_len;
1923
Simon Kelley4cb1b322012-02-06 14:30:41 +00001924 /* avoid buffer overflow */
1925 if (clid_len > 100)
1926 clid_len = 100;
1927
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001928 print_mac(daemon->namebuff, state->clid, clid_len);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001929
1930 if (addr)
1931 {
1932 inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, 255);
1933 strcat(daemon->dhcp_buff2, " ");
1934 }
1935 else
1936 daemon->dhcp_buff2[0] = 0;
1937
1938 if(option_bool(OPT_LOG_OPTS))
Simon Kelley58dc02e2012-02-27 11:49:37 +00001939 my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s %s",
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001940 state->xid,
Simon Kelley4cb1b322012-02-06 14:30:41 +00001941 type,
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001942 state->iface_name,
Simon Kelley4cb1b322012-02-06 14:30:41 +00001943 daemon->dhcp_buff2,
Simon Kelley58dc02e2012-02-27 11:49:37 +00001944 daemon->namebuff,
Simon Kelley4cb1b322012-02-06 14:30:41 +00001945 string ? string : "");
1946 else
Simon Kelley58dc02e2012-02-27 11:49:37 +00001947 my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s %s",
Simon Kelley4cb1b322012-02-06 14:30:41 +00001948 type,
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001949 state->iface_name,
Simon Kelley4cb1b322012-02-06 14:30:41 +00001950 daemon->dhcp_buff2,
Simon Kelley58dc02e2012-02-27 11:49:37 +00001951 daemon->namebuff,
Simon Kelley4cb1b322012-02-06 14:30:41 +00001952 string ? string : "");
1953}
1954
1955static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001956{
1957 u16 opt, opt_len;
1958 void *start;
1959
1960 if (!opts)
1961 return NULL;
1962
1963 while (1)
1964 {
1965 if (end - opts < 4)
1966 return NULL;
1967
1968 start = opts;
1969 GETSHORT(opt, opts);
1970 GETSHORT(opt_len, opts);
1971
1972 if (opt_len > (end - opts))
1973 return NULL;
1974
1975 if (opt == search && (opt_len >= minsize))
1976 return start;
1977
1978 opts += opt_len;
1979 }
1980}
1981
Simon Kelley4cb1b322012-02-06 14:30:41 +00001982static void *opt6_next(void *opts, void *end)
Simon Kelleyc72daea2012-01-05 21:33:27 +00001983{
1984 u16 opt_len;
1985
1986 if (end - opts < 4)
1987 return NULL;
1988
1989 opts += 2;
1990 GETSHORT(opt_len, opts);
1991
1992 if (opt_len >= (end - opts))
1993 return NULL;
1994
1995 return opts + opt_len;
1996}
Simon Kelleyc72daea2012-01-05 21:33:27 +00001997
1998static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
1999{
2000 /* this worries about unaligned data and byte order */
2001 unsigned int ret = 0;
2002 int i;
2003 unsigned char *p = opt6_ptr(opt, offset);
2004
2005 for (i = 0; i < size; i++)
2006 ret = (ret << 8) | *p++;
2007
2008 return ret;
Simon Kelley4cb1b322012-02-06 14:30:41 +00002009}
Simon Kelleyc72daea2012-01-05 21:33:27 +00002010
Simon Kelley8939c952013-09-25 11:49:34 +01002011void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id)
Simon Kelleyff7eea22013-09-04 18:01:38 +01002012{
2013 /* ->local is same value for all relays on ->current chain */
2014
2015 struct all_addr from;
2016 unsigned char *header;
2017 unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2018 int msg_type = *inbuff;
2019 int hopcount;
2020 struct in6_addr multicast;
Simon Kelley8939c952013-09-25 11:49:34 +01002021 unsigned int maclen, mactype;
2022 unsigned char mac[DHCP_CHADDR_MAX];
Simon Kelleyff7eea22013-09-04 18:01:38 +01002023
2024 inet_pton(AF_INET6, ALL_SERVERS, &multicast);
Simon Kelley8939c952013-09-25 11:49:34 +01002025 get_client_mac(peer_address, scope_id, mac, &maclen, &mactype);
2026
Simon Kelleyff7eea22013-09-04 18:01:38 +01002027 /* source address == relay address */
2028 from.addr.addr6 = relay->local.addr.addr6;
2029
2030 /* Get hop count from nested relayed message */
2031 if (msg_type == DHCP6RELAYFORW)
2032 hopcount = *((unsigned char *)inbuff+1) + 1;
2033 else
2034 hopcount = 0;
2035
2036 /* RFC 3315 HOP_COUNT_LIMIT */
2037 if (hopcount > 32)
2038 return;
2039
2040 save_counter(0);
2041
2042 if ((header = put_opt6(NULL, 34)))
2043 {
2044 int o;
2045
2046 header[0] = DHCP6RELAYFORW;
2047 header[1] = hopcount;
2048 memcpy(&header[2], &relay->local.addr.addr6, IN6ADDRSZ);
2049 memcpy(&header[18], peer_address, IN6ADDRSZ);
Simon Kelley89500e32013-09-20 16:29:20 +01002050
2051 /* RFC-6939 */
Simon Kelley8939c952013-09-25 11:49:34 +01002052 if (maclen != 0)
Simon Kelley89500e32013-09-20 16:29:20 +01002053 {
2054 o = new_opt6(OPTION6_CLIENT_MAC);
Simon Kelley8939c952013-09-25 11:49:34 +01002055 put_opt6_short(mactype);
2056 put_opt6(mac, maclen);
Simon Kelley89500e32013-09-20 16:29:20 +01002057 end_opt6(o);
2058 }
Simon Kelleyff7eea22013-09-04 18:01:38 +01002059
2060 o = new_opt6(OPTION6_RELAY_MSG);
2061 put_opt6(inbuff, sz);
2062 end_opt6(o);
2063
2064 for (; relay; relay = relay->current)
2065 {
2066 union mysockaddr to;
2067
2068 to.sa.sa_family = AF_INET6;
2069 to.in6.sin6_addr = relay->server.addr.addr6;
2070 to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
2071 to.in6.sin6_flowinfo = 0;
2072 to.in6.sin6_scope_id = 0;
2073
2074 if (IN6_ARE_ADDR_EQUAL(&relay->server.addr.addr6, &multicast))
2075 {
2076 int multicast_iface;
2077 if (!relay->interface || strchr(relay->interface, '*') ||
2078 (multicast_iface = if_nametoindex(relay->interface)) == 0 ||
2079 setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
2080 my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
2081 }
2082
2083 send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(0), &to, &from, 0);
2084
2085 if (option_bool(OPT_LOG_OPTS))
2086 {
2087 inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
2088 inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
2089 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff);
2090 }
2091
2092 /* Save this for replies */
2093 relay->iface_index = scope_id;
2094 }
2095 }
2096}
2097
2098unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
2099{
2100 struct dhcp_relay *relay;
2101 struct in6_addr link;
2102 unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2103
2104 /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
2105 which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
2106
2107 if (sz < 38 || *inbuff != DHCP6RELAYREPL)
2108 return 0;
2109
2110 memcpy(&link, &inbuff[2], IN6ADDRSZ);
2111
2112 for (relay = daemon->relay6; relay; relay = relay->next)
2113 if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr.addr6) &&
2114 (!relay->interface || wildcard_match(relay->interface, arrival_interface)))
2115 break;
2116
2117 save_counter(0);
2118
2119 if (relay)
2120 {
2121 void *opt, *opts = inbuff + 34;
2122 void *end = inbuff + sz;
2123 for (opt = opts; opt; opt = opt6_next(opt, end))
2124 if (opt6_type(opt) == OPTION6_RELAY_MSG && opt6_len(opt) > 0)
2125 {
2126 int encap_type = *((unsigned char *)opt6_ptr(opt, 0));
2127 put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
2128 memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
2129 peer->sin6_scope_id = relay->iface_index;
2130 return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
2131 }
2132 }
2133
2134 return 0;
2135}
2136
Simon Kelleyc72daea2012-01-05 21:33:27 +00002137#endif