Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
Path: blob/a-new-beginning/SharedDependencies/Sources/libslirp/dhcpv6.c
2 views
1
/* SPDX-License-Identifier: BSD-3-Clause */
2
/*
3
* SLIRP stateless DHCPv6
4
*
5
* We only support stateless DHCPv6, e.g. for network booting.
6
* See RFC 3315, RFC 3736, RFC 3646 and RFC 5970 for details.
7
*
8
* Copyright 2016 Thomas Huth, Red Hat Inc.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
*
14
* 1. Redistributions of source code must retain the above
15
* copyright notice, this list of conditions and the following
16
* disclaimer.
17
*
18
* 2. Redistributions in binary form must reproduce the above
19
* copyright notice, this list of conditions and the following
20
* disclaimer in the documentation and/or other materials provided
21
* with the distribution.
22
*
23
* 3. Neither the name of the copyright holder nor the names of its
24
* contributors may be used to endorse or promote products derived
25
* from this software without specific prior written permission.
26
*
27
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
32
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
38
* OF THE POSSIBILITY OF SUCH DAMAGE.
39
*/
40
41
#include "slirp.h"
42
#include "dhcpv6.h"
43
44
/* DHCPv6 message types */
45
#define MSGTYPE_REPLY 7
46
#define MSGTYPE_INFO_REQUEST 11
47
48
/* DHCPv6 option types */
49
#define OPTION_CLIENTID 1
50
#define OPTION_IAADDR 5
51
#define OPTION_ORO 6
52
#define OPTION_DNS_SERVERS 23
53
#define OPTION_BOOTFILE_URL 59
54
55
struct requested_infos {
56
uint8_t *client_id;
57
int client_id_len;
58
bool want_dns;
59
bool want_boot_url;
60
};
61
62
/**
63
* Analyze the info request message sent by the client to see what data it
64
* provided and what it wants to have. The information is gathered in the
65
* "requested_infos" struct. Note that client_id (if provided) points into
66
* the odata region, thus the caller must keep odata valid as long as it
67
* needs to access the requested_infos struct.
68
*/
69
static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen,
70
struct requested_infos *ri)
71
{
72
int i, req_opt;
73
74
while (olen > 4) {
75
/* Parse one option */
76
int option = odata[0] << 8 | odata[1];
77
int len = odata[2] << 8 | odata[3];
78
79
if (len + 4 > olen) {
80
slirp->cb->guest_error("Guest sent bad DHCPv6 packet!",
81
slirp->opaque);
82
return -E2BIG;
83
}
84
85
switch (option) {
86
case OPTION_IAADDR:
87
/* According to RFC3315, we must discard requests with IA option */
88
return -EINVAL;
89
case OPTION_CLIENTID:
90
if (len > 256) {
91
/* Avoid very long IDs which could cause problems later */
92
return -E2BIG;
93
}
94
ri->client_id = odata + 4;
95
ri->client_id_len = len;
96
break;
97
case OPTION_ORO: /* Option request option */
98
if (len & 1) {
99
return -EINVAL;
100
}
101
/* Check which options the client wants to have */
102
for (i = 0; i < len; i += 2) {
103
req_opt = odata[4 + i] << 8 | odata[4 + i + 1];
104
switch (req_opt) {
105
case OPTION_DNS_SERVERS:
106
ri->want_dns = true;
107
break;
108
case OPTION_BOOTFILE_URL:
109
ri->want_boot_url = true;
110
break;
111
default:
112
DEBUG_MISC("dhcpv6: Unsupported option request %d",
113
req_opt);
114
}
115
}
116
break;
117
default:
118
DEBUG_MISC("dhcpv6 info req: Unsupported option %d, len=%d", option,
119
len);
120
}
121
122
odata += len + 4;
123
olen -= len + 4;
124
}
125
126
return 0;
127
}
128
129
130
/**
131
* Handle information request messages
132
*/
133
static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas,
134
uint32_t xid, uint8_t *odata, int olen)
135
{
136
struct requested_infos ri = { NULL };
137
struct sockaddr_in6 sa6, da6;
138
struct mbuf *m;
139
uint8_t *resp;
140
141
if (dhcpv6_parse_info_request(slirp, odata, olen, &ri) < 0) {
142
return;
143
}
144
145
m = m_get(slirp);
146
if (!m) {
147
return;
148
}
149
memset(m->m_data, 0, m->m_size);
150
m->m_data += IF_MAXLINKHDR;
151
resp = (uint8_t *)m->m_data + sizeof(struct ip6) + sizeof(struct udphdr);
152
153
/* Fill in response */
154
*resp++ = MSGTYPE_REPLY;
155
*resp++ = (uint8_t)(xid >> 16);
156
*resp++ = (uint8_t)(xid >> 8);
157
*resp++ = (uint8_t)xid;
158
159
if (ri.client_id) {
160
*resp++ = OPTION_CLIENTID >> 8; /* option-code high byte */
161
*resp++ = OPTION_CLIENTID; /* option-code low byte */
162
*resp++ = ri.client_id_len >> 8; /* option-len high byte */
163
*resp++ = ri.client_id_len; /* option-len low byte */
164
memcpy(resp, ri.client_id, ri.client_id_len);
165
resp += ri.client_id_len;
166
}
167
if (ri.want_dns) {
168
*resp++ = OPTION_DNS_SERVERS >> 8; /* option-code high byte */
169
*resp++ = OPTION_DNS_SERVERS; /* option-code low byte */
170
*resp++ = 0; /* option-len high byte */
171
*resp++ = 16; /* option-len low byte */
172
memcpy(resp, &slirp->vnameserver_addr6, 16);
173
resp += 16;
174
}
175
if (ri.want_boot_url) {
176
uint8_t *sa = slirp->vhost_addr6.s6_addr;
177
int slen, smaxlen;
178
179
*resp++ = OPTION_BOOTFILE_URL >> 8; /* option-code high byte */
180
*resp++ = OPTION_BOOTFILE_URL; /* option-code low byte */
181
smaxlen = (uint8_t *)m->m_data + slirp->if_mtu - (resp + 2);
182
slen = slirp_fmt((char *)resp + 2, smaxlen,
183
"tftp://[%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
184
"%02x%02x:%02x%02x:%02x%02x:%02x%02x]/%s",
185
sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7],
186
sa[8], sa[9], sa[10], sa[11], sa[12], sa[13], sa[14],
187
sa[15], slirp->bootp_filename);
188
*resp++ = slen >> 8; /* option-len high byte */
189
*resp++ = slen; /* option-len low byte */
190
resp += slen;
191
}
192
193
sa6.sin6_addr = slirp->vhost_addr6;
194
sa6.sin6_port = DHCPV6_SERVER_PORT;
195
da6.sin6_addr = srcsas->sin6_addr;
196
da6.sin6_port = srcsas->sin6_port;
197
m->m_data += sizeof(struct ip6) + sizeof(struct udphdr);
198
m->m_len = resp - (uint8_t *)m->m_data;
199
udp6_output(NULL, m, &sa6, &da6);
200
}
201
202
/**
203
* Handle DHCPv6 messages sent by the client
204
*/
205
void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m)
206
{
207
uint8_t *data = (uint8_t *)m->m_data + sizeof(struct udphdr);
208
int data_len = m->m_len - sizeof(struct udphdr);
209
uint32_t xid;
210
211
if (data_len < 4) {
212
return;
213
}
214
215
xid = ntohl(*(uint32_t *)data) & 0xffffff;
216
217
switch (data[0]) {
218
case MSGTYPE_INFO_REQUEST:
219
dhcpv6_info_request(m->slirp, srcsas, xid, &data[4], data_len - 4);
220
break;
221
default:
222
DEBUG_MISC("dhcpv6_input: Unsupported message type 0x%x", data[0]);
223
}
224
}
225
226