Print this page
7388 Support DHCP Client FQDN. Allow IAID/DUID for all v4.
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libipadm/common/libipadm.c
+++ new/usr/src/lib/libipadm/common/libipadm.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 + * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
25 26 */
26 27
27 28 #include <stdio.h>
28 29 #include <stdlib.h>
29 30 #include <string.h>
30 31 #include <errno.h>
31 32 #include <fcntl.h>
32 33 #include <unistd.h>
33 34 #include <stropts.h>
34 35 #include <sys/sockio.h>
35 36 #include <sys/types.h>
36 37 #include <sys/stat.h>
37 38 #include <sys/socket.h>
38 39 #include <net/route.h>
39 40 #include <netinet/in.h>
40 41 #include <inet/ip.h>
41 42 #include <arpa/inet.h>
42 43 #include <libintl.h>
43 44 #include <libdlpi.h>
44 45 #include <libinetutil.h>
45 46 #include <libdladm.h>
46 47 #include <libdllink.h>
47 48 #include <libdliptun.h>
48 49 #include <strings.h>
49 50 #include <zone.h>
50 51 #include <ctype.h>
51 52 #include <limits.h>
52 53 #include <assert.h>
53 54 #include <netdb.h>
54 55 #include <pwd.h>
55 56 #include <auth_attr.h>
56 57 #include <secdb.h>
57 58 #include <nss_dbdefs.h>
58 59 #include "libipadm_impl.h"
59 60
60 61 /* error codes and text description */
61 62 static struct ipadm_error_info {
62 63 ipadm_status_t error_code;
63 64 const char *error_desc;
64 65 } ipadm_errors[] = {
65 66 { IPADM_SUCCESS, "Operation succeeded" },
66 67 { IPADM_FAILURE, "Operation failed" },
67 68 { IPADM_EAUTH, "Insufficient user authorizations" },
68 69 { IPADM_EPERM, "Permission denied" },
69 70 { IPADM_NO_BUFS, "No buffer space available" },
70 71 { IPADM_NO_MEMORY, "Insufficient memory" },
71 72 { IPADM_BAD_ADDR, "Invalid address" },
72 73 { IPADM_BAD_PROTOCOL, "Incorrect protocol family for operation" },
73 74 { IPADM_DAD_FOUND, "Duplicate address detected" },
74 75 { IPADM_EXISTS, "Already exists" },
75 76 { IPADM_IF_EXISTS, "Interface already exists" },
76 77 { IPADM_ADDROBJ_EXISTS, "Address object already exists" },
77 78 { IPADM_ADDRCONF_EXISTS, "Addrconf already in progress" },
78 79 { IPADM_ENXIO, "Interface does not exist" },
79 80 { IPADM_GRP_NOTEMPTY, "IPMP group is not empty" },
80 81 { IPADM_INVALID_ARG, "Invalid argument provided" },
81 82 { IPADM_INVALID_NAME, "Invalid name" },
82 83 { IPADM_DLPI_FAILURE, "Could not open DLPI link" },
83 84 { IPADM_DLADM_FAILURE, "Datalink does not exist" },
84 85 { IPADM_PROP_UNKNOWN, "Unknown property" },
85 86 { IPADM_ERANGE, "Value is outside the allowed range" },
86 87 { IPADM_ESRCH, "Value does not exist" },
87 88 { IPADM_EOVERFLOW, "Number of values exceeds the allowed limit" },
88 89 { IPADM_NOTFOUND, "Object not found" },
89 90 { IPADM_IF_INUSE, "Interface already in use" },
90 91 { IPADM_ADDR_INUSE, "Address already in use" },
91 92 { IPADM_BAD_HOSTNAME, "Hostname maps to multiple IP addresses" },
92 93 { IPADM_ADDR_NOTAVAIL, "Can't assign requested address" },
93 94 { IPADM_ALL_ADDRS_NOT_ENABLED, "All addresses could not be enabled" },
94 95 { IPADM_NDPD_NOT_RUNNING, "IPv6 autoconf daemon in.ndpd not running" },
95 96 { IPADM_DHCP_START_ERROR, "Could not start dhcpagent" },
96 97 { IPADM_DHCP_IPC_ERROR, "Could not communicate with dhcpagent" },
97 98 { IPADM_DHCP_IPC_TIMEOUT, "Communication with dhcpagent timed out" },
98 99 { IPADM_TEMPORARY_OBJ, "Persistent operation on temporary object" },
99 100 { IPADM_IPC_ERROR, "Could not communicate with ipmgmtd" },
100 101 { IPADM_NOTSUP, "Operation not supported" },
101 102 { IPADM_OP_DISABLE_OBJ, "Operation not supported on disabled object" },
102 103 { IPADM_EBADE, "Invalid data exchange with daemon" },
103 104 { IPADM_GZ_PERM, "Operation not permitted on from-gz interface"}
104 105 };
105 106
106 107 #define IPADM_NUM_ERRORS (sizeof (ipadm_errors) / sizeof (*ipadm_errors))
107 108
108 109 ipadm_status_t
109 110 ipadm_errno2status(int error)
110 111 {
111 112 switch (error) {
112 113 case 0:
113 114 return (IPADM_SUCCESS);
114 115 case ENXIO:
115 116 return (IPADM_ENXIO);
116 117 case ENOMEM:
117 118 return (IPADM_NO_MEMORY);
118 119 case ENOBUFS:
119 120 return (IPADM_NO_BUFS);
120 121 case EINVAL:
121 122 return (IPADM_INVALID_ARG);
122 123 case EBUSY:
123 124 return (IPADM_IF_INUSE);
124 125 case EEXIST:
125 126 return (IPADM_EXISTS);
126 127 case EADDRNOTAVAIL:
127 128 return (IPADM_ADDR_NOTAVAIL);
128 129 case EADDRINUSE:
129 130 return (IPADM_ADDR_INUSE);
130 131 case ENOENT:
131 132 return (IPADM_NOTFOUND);
132 133 case ERANGE:
133 134 return (IPADM_ERANGE);
134 135 case EPERM:
135 136 return (IPADM_EPERM);
136 137 case ENOTSUP:
137 138 case EOPNOTSUPP:
138 139 return (IPADM_NOTSUP);
139 140 case EBADF:
140 141 return (IPADM_IPC_ERROR);
141 142 case EBADE:
142 143 return (IPADM_EBADE);
143 144 case ESRCH:
144 145 return (IPADM_ESRCH);
145 146 case EOVERFLOW:
146 147 return (IPADM_EOVERFLOW);
147 148 default:
148 149 return (IPADM_FAILURE);
149 150 }
150 151 }
151 152
152 153 /*
153 154 * Returns a message string for the given libipadm error status.
154 155 */
155 156 const char *
156 157 ipadm_status2str(ipadm_status_t status)
157 158 {
158 159 int i;
159 160
160 161 for (i = 0; i < IPADM_NUM_ERRORS; i++) {
161 162 if (status == ipadm_errors[i].error_code)
162 163 return (dgettext(TEXT_DOMAIN,
163 164 ipadm_errors[i].error_desc));
164 165 }
165 166
166 167 return (dgettext(TEXT_DOMAIN, "<unknown error>"));
167 168 }
168 169
169 170 /*
170 171 * Opens a handle to libipadm.
171 172 * Possible values for flags:
172 173 * IPH_VRRP: Used by VRRP daemon to set the socket option SO_VRRP.
173 174 * IPH_LEGACY: This is used whenever an application needs to provide a
174 175 * logical interface name while creating or deleting
175 176 * interfaces and static addresses.
176 177 * IPH_INIT: Used by ipadm_init_prop(), to initialize protocol properties
177 178 * on reboot.
178 179 */
179 180 ipadm_status_t
180 181 ipadm_open(ipadm_handle_t *handle, uint32_t flags)
181 182 {
182 183 ipadm_handle_t iph;
183 184 ipadm_status_t status = IPADM_SUCCESS;
184 185 zoneid_t zoneid;
185 186 ushort_t zflags;
186 187 int on = B_TRUE;
187 188
188 189 if (handle == NULL)
189 190 return (IPADM_INVALID_ARG);
190 191 *handle = NULL;
191 192
192 193 if (flags & ~(IPH_VRRP|IPH_LEGACY|IPH_INIT|IPH_IPMGMTD))
193 194 return (IPADM_INVALID_ARG);
194 195
195 196 if ((iph = calloc(1, sizeof (struct ipadm_handle))) == NULL)
196 197 return (IPADM_NO_MEMORY);
197 198 iph->iph_sock = -1;
198 199 iph->iph_sock6 = -1;
199 200 iph->iph_door_fd = -1;
200 201 iph->iph_rtsock = -1;
201 202 iph->iph_flags = flags;
202 203 (void) pthread_mutex_init(&iph->iph_lock, NULL);
203 204
204 205 if ((iph->iph_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
205 206 (iph->iph_sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
206 207 goto errnofail;
207 208 }
208 209
209 210 /*
210 211 * We open a handle to libdladm here, to facilitate some daemons (like
211 212 * nwamd) which opens handle to libipadm before devfsadmd installs the
212 213 * right device permissions into the kernel and requires "all"
213 214 * privileges to open DLD_CONTROL_DEV.
214 215 *
215 216 * In a non-global shared-ip zone there will be no DLD_CONTROL_DEV node
216 217 * and dladm_open() will fail. So, we avoid this by not calling
217 218 * dladm_open() for such zones.
218 219 */
219 220 zoneid = getzoneid();
220 221 iph->iph_zoneid = zoneid;
221 222 if (zoneid != GLOBAL_ZONEID) {
222 223 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags,
223 224 sizeof (zflags)) < 0) {
224 225 goto errnofail;
225 226 }
226 227 }
227 228 if ((zoneid == GLOBAL_ZONEID) || (zflags & ZF_NET_EXCL)) {
228 229 if (dladm_open(&iph->iph_dlh) != DLADM_STATUS_OK) {
229 230 ipadm_close(iph);
230 231 return (IPADM_DLADM_FAILURE);
231 232 }
232 233 if (zoneid != GLOBAL_ZONEID) {
233 234 iph->iph_rtsock = socket(PF_ROUTE, SOCK_RAW, 0);
234 235 /*
235 236 * Failure to open rtsock is ignored as this is
236 237 * only used in non-global zones to initialize
237 238 * routing socket information.
238 239 */
239 240 }
240 241 } else {
241 242 assert(zoneid != GLOBAL_ZONEID);
242 243 iph->iph_dlh = NULL;
243 244 }
244 245 if (flags & IPH_VRRP) {
245 246 if (setsockopt(iph->iph_sock6, SOL_SOCKET, SO_VRRP, &on,
246 247 sizeof (on)) < 0 || setsockopt(iph->iph_sock, SOL_SOCKET,
247 248 SO_VRRP, &on, sizeof (on)) < 0) {
248 249 goto errnofail;
249 250 }
250 251 }
251 252 *handle = iph;
252 253 return (status);
253 254
254 255 errnofail:
255 256 status = ipadm_errno2status(errno);
256 257 ipadm_close(iph);
257 258 return (status);
258 259 }
259 260
260 261 /*
261 262 * Closes and frees the libipadm handle.
262 263 */
263 264 void
264 265 ipadm_close(ipadm_handle_t iph)
265 266 {
266 267 if (iph == NULL)
267 268 return;
268 269 if (iph->iph_sock != -1)
269 270 (void) close(iph->iph_sock);
270 271 if (iph->iph_sock6 != -1)
271 272 (void) close(iph->iph_sock6);
272 273 if (iph->iph_rtsock != -1)
273 274 (void) close(iph->iph_rtsock);
274 275 if (iph->iph_door_fd != -1)
275 276 (void) close(iph->iph_door_fd);
276 277 dladm_close(iph->iph_dlh);
277 278 (void) pthread_mutex_destroy(&iph->iph_lock);
278 279 free(iph);
279 280 }
280 281
281 282 /*
282 283 * Checks if the caller has the authorization to configure network
283 284 * interfaces.
284 285 */
285 286 boolean_t
286 287 ipadm_check_auth(void)
287 288 {
288 289 struct passwd pwd;
289 290 char buf[NSS_BUFLEN_PASSWD];
290 291
291 292 /* get the password entry for the given user ID */
292 293 if (getpwuid_r(getuid(), &pwd, buf, sizeof (buf)) == NULL)
293 294 return (B_FALSE);
294 295
295 296 /* check for presence of given authorization */
296 297 return (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH, pwd.pw_name) != 0);
297 298 }
298 299
299 300 /*
300 301 * Stores the index value of the interface in `ifname' for the address
301 302 * family `af' into the buffer pointed to by `index'.
302 303 */
303 304 static ipadm_status_t
304 305 i_ipadm_get_index(ipadm_handle_t iph, const char *ifname, sa_family_t af,
305 306 int *index)
306 307 {
307 308 struct lifreq lifr;
308 309 int sock;
309 310
310 311 bzero(&lifr, sizeof (lifr));
311 312 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
312 313 if (af == AF_INET)
313 314 sock = iph->iph_sock;
314 315 else
315 316 sock = iph->iph_sock6;
316 317
317 318 if (ioctl(sock, SIOCGLIFINDEX, (caddr_t)&lifr) < 0)
318 319 return (ipadm_errno2status(errno));
319 320 *index = lifr.lifr_index;
320 321
321 322 return (IPADM_SUCCESS);
322 323 }
323 324
324 325 /*
325 326 * Maximum amount of time (in milliseconds) to wait for Duplicate Address
326 327 * Detection to complete in the kernel.
327 328 */
328 329 #define DAD_WAIT_TIME 1000
329 330
330 331 /*
331 332 * Any time that flags are changed on an interface where either the new or the
332 333 * existing flags have IFF_UP set, we'll get a RTM_NEWADDR message to
333 334 * announce the new address added and its flag status.
334 335 * We wait here for that message and look for IFF_UP.
335 336 * If something's amiss with the kernel, though, we don't wait forever.
336 337 * (Note that IFF_DUPLICATE is a high-order bit, and we cannot see
337 338 * it in the routing socket messages.)
338 339 */
339 340 static ipadm_status_t
340 341 i_ipadm_dad_wait(ipadm_handle_t handle, const char *lifname, sa_family_t af,
341 342 int rtsock)
342 343 {
343 344 struct pollfd fds[1];
344 345 union {
345 346 struct if_msghdr ifm;
346 347 char buf[1024];
347 348 } msg;
348 349 int index;
349 350 ipadm_status_t retv;
350 351 uint64_t flags;
351 352 hrtime_t starttime, now;
352 353
353 354 fds[0].fd = rtsock;
354 355 fds[0].events = POLLIN;
355 356 fds[0].revents = 0;
356 357
357 358 retv = i_ipadm_get_index(handle, lifname, af, &index);
358 359 if (retv != IPADM_SUCCESS)
359 360 return (retv);
360 361
361 362 starttime = gethrtime();
362 363 for (;;) {
363 364 now = gethrtime();
364 365 now = (now - starttime) / 1000000;
365 366 if (now >= DAD_WAIT_TIME)
366 367 break;
367 368 if (poll(fds, 1, DAD_WAIT_TIME - (int)now) <= 0)
368 369 break;
369 370 if (read(rtsock, &msg, sizeof (msg)) <= 0)
370 371 break;
371 372 if (msg.ifm.ifm_type != RTM_NEWADDR)
372 373 continue;
373 374 /* Note that ifm_index is just 16 bits */
374 375 if (index == msg.ifm.ifm_index && (msg.ifm.ifm_flags & IFF_UP))
375 376 return (IPADM_SUCCESS);
376 377 }
377 378
378 379 retv = i_ipadm_get_flags(handle, lifname, af, &flags);
379 380 if (retv != IPADM_SUCCESS)
380 381 return (retv);
381 382 if (flags & IFF_DUPLICATE)
382 383 return (IPADM_DAD_FOUND);
383 384
384 385 return (IPADM_SUCCESS);
385 386 }
386 387
387 388 /*
388 389 * Sets the flags `on_flags' and resets the flags `off_flags' for the logical
389 390 * interface in `lifname'.
390 391 *
391 392 * If the new flags value will transition the interface from "down" to "up"
392 393 * then duplicate address detection is performed by the kernel. This routine
393 394 * waits to get the outcome of that test.
394 395 */
395 396 ipadm_status_t
396 397 i_ipadm_set_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af,
397 398 uint64_t on_flags, uint64_t off_flags)
398 399 {
399 400 struct lifreq lifr;
400 401 uint64_t oflags;
401 402 ipadm_status_t ret;
402 403 int rtsock = -1;
403 404 int sock, err;
404 405
405 406 ret = i_ipadm_get_flags(iph, lifname, af, &oflags);
406 407 if (ret != IPADM_SUCCESS)
407 408 return (ret);
408 409
409 410 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
410 411
411 412 /*
412 413 * Any time flags are changed on an interface that has IFF_UP set,
413 414 * we get a routing socket message. We care about the status,
414 415 * though, only when the new flags are marked "up."
415 416 */
416 417 if (!(oflags & IFF_UP) && (on_flags & IFF_UP))
417 418 rtsock = socket(PF_ROUTE, SOCK_RAW, af);
418 419
419 420 oflags |= on_flags;
420 421 oflags &= ~off_flags;
421 422 bzero(&lifr, sizeof (lifr));
422 423 (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
423 424 lifr.lifr_flags = oflags;
424 425 if (ioctl(sock, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
425 426 err = errno;
426 427 if (rtsock != -1)
427 428 (void) close(rtsock);
428 429 return (ipadm_errno2status(err));
429 430 }
430 431 if (rtsock == -1) {
431 432 return (IPADM_SUCCESS);
432 433 } else {
433 434 /* Wait for DAD to complete. */
434 435 ret = i_ipadm_dad_wait(iph, lifname, af, rtsock);
435 436 (void) close(rtsock);
436 437 return (ret);
437 438 }
438 439 }
439 440
440 441 /*
441 442 * Returns the flags value for the logical interface in `lifname'
442 443 * in the buffer pointed to by `flags'.
443 444 */
444 445 ipadm_status_t
445 446 i_ipadm_get_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af,
446 447 uint64_t *flags)
447 448 {
448 449 struct lifreq lifr;
449 450 int sock;
450 451
451 452 bzero(&lifr, sizeof (lifr));
452 453 (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
453 454 if (af == AF_INET)
454 455 sock = iph->iph_sock;
455 456 else
456 457 sock = iph->iph_sock6;
457 458
458 459 if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
459 460 return (ipadm_errno2status(errno));
460 461 }
461 462 *flags = lifr.lifr_flags;
462 463
463 464 return (IPADM_SUCCESS);
464 465 }
465 466
466 467 /*
467 468 * Determines whether or not an interface name represents a loopback
468 469 * interface, before the interface has been plumbed.
469 470 * It is assumed that the interface name in `ifname' is of correct format
470 471 * as verified by ifparse_ifspec().
471 472 *
472 473 * Returns: B_TRUE if loopback, B_FALSE if not.
473 474 */
474 475 boolean_t
475 476 i_ipadm_is_loopback(const char *ifname)
476 477 {
477 478 int len = strlen(LOOPBACK_IF);
478 479
479 480 return (strncmp(ifname, LOOPBACK_IF, len) == 0 &&
480 481 (ifname[len] == '\0' || ifname[len] == IPADM_LOGICAL_SEP));
481 482 }
482 483
483 484 /*
484 485 * Determines whether or not an interface name represents a vni
485 486 * interface, before the interface has been plumbed.
486 487 * It is assumed that the interface name in `ifname' is of correct format
487 488 * as verified by ifparse_ifspec().
488 489 *
489 490 * Returns: B_TRUE if vni, B_FALSE if not.
490 491 */
491 492 boolean_t
492 493 i_ipadm_is_vni(const char *ifname)
493 494 {
494 495 ifspec_t ifsp;
495 496
496 497 return (ifparse_ifspec(ifname, &ifsp) &&
497 498 strcmp(ifsp.ifsp_devnm, "vni") == 0);
498 499 }
499 500
500 501 /*
501 502 * Returns B_TRUE if `ifname' is an IP interface on a 6to4 tunnel.
502 503 */
503 504 boolean_t
504 505 i_ipadm_is_6to4(ipadm_handle_t iph, char *ifname)
505 506 {
506 507 dladm_status_t dlstatus;
507 508 datalink_class_t class;
508 509 iptun_params_t params;
509 510 datalink_id_t linkid;
510 511
511 512 if (iph->iph_dlh == NULL) {
512 513 assert(iph->iph_zoneid != GLOBAL_ZONEID);
513 514 return (B_FALSE);
514 515 }
515 516 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL,
516 517 &class, NULL);
517 518 if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) {
518 519 params.iptun_param_linkid = linkid;
519 520 dlstatus = dladm_iptun_getparams(iph->iph_dlh, ¶ms,
520 521 DLADM_OPT_ACTIVE);
521 522 if (dlstatus == DLADM_STATUS_OK &&
522 523 params.iptun_param_type == IPTUN_TYPE_6TO4) {
523 524 return (B_TRUE);
524 525 }
525 526 }
526 527 return (B_FALSE);
527 528 }
528 529
529 530 /*
530 531 * Returns B_TRUE if `ifname' represents an IPMP underlying interface.
531 532 */
532 533 boolean_t
533 534 i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname)
534 535 {
535 536 struct lifreq lifr;
536 537
537 538 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
538 539 if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0) {
539 540 if (ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME,
540 541 (caddr_t)&lifr) < 0) {
541 542 return (B_FALSE);
542 543 }
543 544 }
544 545 return (lifr.lifr_groupname[0] != '\0');
545 546 }
546 547
547 548 /*
548 549 * Returns B_TRUE if `ifname' represents an IPMP meta-interface.
549 550 */
550 551 boolean_t
551 552 i_ipadm_is_ipmp(ipadm_handle_t iph, const char *ifname)
552 553 {
553 554 uint64_t flags;
554 555
555 556 if (i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS &&
556 557 i_ipadm_get_flags(iph, ifname, AF_INET6, &flags) != IPADM_SUCCESS)
557 558 return (B_FALSE);
558 559
559 560 return ((flags & IFF_IPMP) != 0);
560 561 }
561 562
562 563 /*
563 564 * For a given interface name, ipadm_if_enabled() checks if v4
564 565 * or v6 or both IP interfaces exist in the active configuration.
565 566 */
566 567 boolean_t
567 568 ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af)
568 569 {
569 570 struct lifreq lifr;
570 571 int s4 = iph->iph_sock;
571 572 int s6 = iph->iph_sock6;
572 573
573 574 bzero(&lifr, sizeof (lifr));
574 575 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
575 576 switch (af) {
576 577 case AF_INET:
577 578 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
578 579 return (B_TRUE);
579 580 break;
580 581 case AF_INET6:
581 582 if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
582 583 return (B_TRUE);
583 584 break;
584 585 case AF_UNSPEC:
585 586 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0 ||
586 587 ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) {
587 588 return (B_TRUE);
588 589 }
589 590 }
590 591 return (B_FALSE);
591 592 }
592 593
593 594 /*
594 595 * Apply the interface property by retrieving information from nvl.
595 596 */
596 597 static ipadm_status_t
597 598 i_ipadm_init_ifprop(ipadm_handle_t iph, nvlist_t *nvl)
598 599 {
599 600 nvpair_t *nvp;
600 601 char *name, *pname = NULL;
601 602 char *protostr = NULL, *ifname = NULL, *pval = NULL;
602 603 uint_t proto;
603 604 int err = 0;
604 605
605 606 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
606 607 nvp = nvlist_next_nvpair(nvl, nvp)) {
607 608 name = nvpair_name(nvp);
608 609 if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
609 610 if ((err = nvpair_value_string(nvp, &ifname)) != 0)
610 611 break;
611 612 } else if (strcmp(name, IPADM_NVP_PROTONAME) == 0) {
612 613 if ((err = nvpair_value_string(nvp, &protostr)) != 0)
613 614 break;
614 615 } else {
615 616 assert(!IPADM_PRIV_NVP(name));
616 617 pname = name;
617 618 if ((err = nvpair_value_string(nvp, &pval)) != 0)
618 619 break;
619 620 }
620 621 }
621 622 if (err != 0)
622 623 return (ipadm_errno2status(err));
623 624 proto = ipadm_str2proto(protostr);
624 625 return (ipadm_set_ifprop(iph, ifname, pname, pval, proto,
625 626 IPADM_OPT_ACTIVE));
626 627 }
627 628
628 629 /*
629 630 * Instantiate the address object or set the address object property by
630 631 * retrieving the configuration from the nvlist `nvl'.
631 632 */
632 633 ipadm_status_t
633 634 i_ipadm_init_addrobj(ipadm_handle_t iph, nvlist_t *nvl)
634 635 {
635 636 nvpair_t *nvp;
636 637 char *name;
637 638 char *aobjname = NULL, *pval = NULL, *ifname = NULL;
638 639 sa_family_t af = AF_UNSPEC;
639 640 ipadm_addr_type_t atype = IPADM_ADDR_NONE;
640 641 int err = 0;
641 642 ipadm_status_t status = IPADM_SUCCESS;
642 643
643 644 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
644 645 nvp = nvlist_next_nvpair(nvl, nvp)) {
645 646 name = nvpair_name(nvp);
646 647 if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
647 648 if ((err = nvpair_value_string(nvp, &ifname)) != 0)
648 649 break;
649 650 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
650 651 if ((err = nvpair_value_string(nvp, &aobjname)) != 0)
651 652 break;
652 653 } else if (i_ipadm_name2atype(name, &af, &atype)) {
653 654 break;
654 655 } else {
655 656 assert(!IPADM_PRIV_NVP(name));
656 657 err = nvpair_value_string(nvp, &pval);
657 658 break;
658 659 }
659 660 }
660 661 if (err != 0)
661 662 return (ipadm_errno2status(err));
662 663
663 664 switch (atype) {
664 665 case IPADM_ADDR_STATIC:
665 666 status = i_ipadm_enable_static(iph, ifname, nvl, af);
666 667 break;
667 668 case IPADM_ADDR_DHCP:
668 669 status = i_ipadm_enable_dhcp(iph, ifname, nvl);
669 670 if (status == IPADM_DHCP_IPC_TIMEOUT)
670 671 status = IPADM_SUCCESS;
671 672 break;
672 673 case IPADM_ADDR_IPV6_ADDRCONF:
673 674 status = i_ipadm_enable_addrconf(iph, ifname, nvl);
674 675 break;
675 676 case IPADM_ADDR_NONE:
676 677 status = ipadm_set_addrprop(iph, name, pval, aobjname,
677 678 IPADM_OPT_ACTIVE);
678 679 break;
679 680 }
680 681
681 682 return (status);
682 683 }
683 684
684 685 /*
685 686 * Instantiate the interface object by retrieving the configuration from
686 687 * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration
687 688 * (interface properties and address objects on that interface) for the
688 689 * given `ifname'.
689 690 */
690 691 ipadm_status_t
691 692 i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
692 693 {
693 694 nvlist_t *nvl = NULL;
694 695 nvpair_t *nvp;
695 696 char *afstr;
696 697 ipadm_status_t status;
697 698 ipadm_status_t ret_status = IPADM_SUCCESS;
698 699 char newifname[LIFNAMSIZ];
699 700 char *aobjstr;
700 701 sa_family_t af = AF_UNSPEC;
701 702 boolean_t is_ngz = (iph->iph_zoneid != GLOBAL_ZONEID);
702 703
703 704 (void) strlcpy(newifname, ifname, sizeof (newifname));
704 705 /*
705 706 * First plumb the given interface and then apply all the persistent
706 707 * interface properties and then instantiate any persistent addresses
707 708 * objects on that interface.
708 709 */
709 710 for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
710 711 nvp = nvlist_next_nvpair(ifnvl, nvp)) {
711 712 if (nvpair_value_nvlist(nvp, &nvl) != 0)
712 713 continue;
713 714
714 715 if (nvlist_lookup_string(nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
715 716 status = i_ipadm_plumb_if(iph, newifname, atoi(afstr),
716 717 IPADM_OPT_ACTIVE);
717 718 /*
718 719 * If the interface is already plumbed, we should
719 720 * ignore this error because there might be address
720 721 * address objects on that interface that needs to
|
↓ open down ↓ |
686 lines elided |
↑ open up ↑ |
721 722 * be enabled again.
722 723 */
723 724 if (status == IPADM_IF_EXISTS)
724 725 status = IPADM_SUCCESS;
725 726
726 727 if (is_ngz)
727 728 af = atoi(afstr);
728 729 } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
729 730 &aobjstr) == 0) {
730 731 /*
731 - * For a static address, we need to search for
732 - * the prefixlen in the nvlist `ifnvl'.
732 + * For addresses, we need to relocate addrprops from the
733 + * nvlist `ifnvl'.
733 734 */
734 735 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
735 - nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
736 - status = i_ipadm_merge_prefixlen_from_nvl(ifnvl,
736 + nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
737 + nvlist_exists(nvl, IPADM_NVP_DHCP)) {
738 + status = i_ipadm_merge_addrprops_from_nvl(ifnvl,
737 739 nvl, aobjstr);
738 740 if (status != IPADM_SUCCESS)
739 741 continue;
740 742 }
741 743 status = i_ipadm_init_addrobj(iph, nvl);
742 744 /*
743 745 * If this address is in use on some other interface,
744 746 * we want to record an error to be returned as
745 747 * a soft error and continue processing the rest of
746 748 * the addresses.
747 749 */
748 750 if (status == IPADM_ADDR_NOTAVAIL) {
749 751 ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
750 752 status = IPADM_SUCCESS;
751 753 }
752 754 } else {
753 755 assert(nvlist_exists(nvl, IPADM_NVP_PROTONAME));
754 756 status = i_ipadm_init_ifprop(iph, nvl);
755 757 }
756 758 if (status != IPADM_SUCCESS)
757 759 return (status);
758 760 }
759 761
760 762 if (is_ngz && af != AF_UNSPEC)
761 763 ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
762 764 return (ret_status);
763 765 }
764 766
765 767 /*
766 768 * Retrieves the persistent configuration for the given interface(s) in `ifs'
767 769 * by contacting the daemon and dumps the information in `allifs'.
768 770 */
769 771 ipadm_status_t
770 772 i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs)
771 773 {
772 774 nvlist_t *nvl = NULL;
773 775 size_t nvlsize, bufsize;
774 776 ipmgmt_initif_arg_t *iargp;
775 777 char *buf = NULL, *nvlbuf = NULL;
776 778 ipmgmt_get_rval_t *rvalp = NULL;
777 779 int err;
778 780 ipadm_status_t status = IPADM_SUCCESS;
779 781
780 782 if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0)
781 783 return (ipadm_errno2status(err));
782 784
783 785 err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
784 786 if (err != 0) {
785 787 status = ipadm_errno2status(err);
786 788 goto done;
787 789 }
788 790 bufsize = sizeof (*iargp) + nvlsize;
789 791 if ((buf = malloc(bufsize)) == NULL) {
790 792 status = ipadm_errno2status(errno);
791 793 goto done;
792 794 }
793 795
794 796 /* populate the door_call argument structure */
795 797 iargp = (void *)buf;
796 798 iargp->ia_cmd = IPMGMT_CMD_INITIF;
797 799 iargp->ia_flags = 0;
798 800 iargp->ia_family = AF_UNSPEC;
799 801 iargp->ia_nvlsize = nvlsize;
800 802 (void) bcopy(nvlbuf, buf + sizeof (*iargp), nvlsize);
801 803
802 804 if ((rvalp = malloc(sizeof (ipmgmt_get_rval_t))) == NULL) {
803 805 status = ipadm_errno2status(errno);
804 806 goto done;
805 807 }
806 808 if ((err = ipadm_door_call(iph, iargp, bufsize, (void **)&rvalp,
807 809 sizeof (*rvalp), B_TRUE)) != 0) {
808 810 status = ipadm_errno2status(err);
809 811 goto done;
810 812 }
811 813
812 814 /*
813 815 * Daemon reply pointed to by rvalp contains ipmgmt_get_rval_t structure
814 816 * followed by a list of packed nvlists, each of which represents
815 817 * configuration information for the given interface(s).
816 818 */
817 819 err = nvlist_unpack((char *)rvalp + sizeof (ipmgmt_get_rval_t),
818 820 rvalp->ir_nvlsize, allifs, NV_ENCODE_NATIVE);
819 821 if (err != 0)
820 822 status = ipadm_errno2status(err);
821 823 done:
822 824 nvlist_free(nvl);
823 825 free(buf);
824 826 free(nvlbuf);
825 827 free(rvalp);
826 828 return (status);
827 829 }
828 830
829 831 /*
830 832 * Returns B_FALSE if
831 833 * (1) `ifname' is NULL or has no string or has a string of invalid length
832 834 * (2) ifname is a logical interface and IPH_LEGACY is not set, or
833 835 */
834 836 boolean_t
835 837 i_ipadm_validate_ifname(ipadm_handle_t iph, const char *ifname)
836 838 {
837 839 ifspec_t ifsp;
838 840
839 841 if (ifname == NULL || ifname[0] == '\0' ||
840 842 !ifparse_ifspec(ifname, &ifsp))
841 843 return (B_FALSE);
842 844 if (ifsp.ifsp_lunvalid)
843 845 return (ifsp.ifsp_lun > 0 && (iph->iph_flags & IPH_LEGACY));
844 846 return (B_TRUE);
845 847 }
846 848
847 849 /*
848 850 * Wrapper for sending a non-transparent I_STR ioctl().
849 851 * Returns: Result from ioctl().
850 852 */
851 853 int
852 854 i_ipadm_strioctl(int s, int cmd, char *buf, int buflen)
853 855 {
854 856 struct strioctl ioc;
855 857
856 858 (void) memset(&ioc, 0, sizeof (ioc));
857 859 ioc.ic_cmd = cmd;
858 860 ioc.ic_timout = 0;
859 861 ioc.ic_len = buflen;
860 862 ioc.ic_dp = buf;
861 863
862 864 return (ioctl(s, I_STR, (char *)&ioc));
863 865 }
864 866
865 867 /*
866 868 * Make a door call to the server and checks if the door call succeeded or not.
867 869 * `is_varsize' specifies that the data returned by ipmgmtd daemon is of
868 870 * variable size and door will allocate buffer using mmap(). In such cases
869 871 * we re-allocate the required memory,n assign it to `rbufp', copy the data to
870 872 * `rbufp' and then call munmap() (see below).
871 873 *
872 874 * It also checks to see if the server side procedure ran successfully by
873 875 * checking for ir_err. Therefore, for some callers who just care about the
874 876 * return status can set `rbufp' to NULL and set `rsize' to 0.
875 877 */
876 878 int
877 879 ipadm_door_call(ipadm_handle_t iph, void *arg, size_t asize, void **rbufp,
878 880 size_t rsize, boolean_t is_varsize)
879 881 {
880 882 door_arg_t darg;
881 883 int err;
882 884 ipmgmt_retval_t rval, *rvalp;
883 885 boolean_t reopen = B_FALSE;
884 886
885 887 if (rbufp == NULL) {
886 888 rvalp = &rval;
887 889 rbufp = (void **)&rvalp;
888 890 rsize = sizeof (rval);
889 891 }
890 892
891 893 darg.data_ptr = arg;
892 894 darg.data_size = asize;
893 895 darg.desc_ptr = NULL;
894 896 darg.desc_num = 0;
895 897 darg.rbuf = *rbufp;
896 898 darg.rsize = rsize;
897 899
898 900 reopen:
899 901 (void) pthread_mutex_lock(&iph->iph_lock);
900 902 /* The door descriptor is opened if it isn't already */
901 903 if (iph->iph_door_fd == -1) {
902 904 if ((iph->iph_door_fd = open(IPMGMT_DOOR, O_RDONLY)) < 0) {
903 905 err = errno;
904 906 (void) pthread_mutex_unlock(&iph->iph_lock);
905 907 return (err);
906 908 }
907 909 }
908 910 (void) pthread_mutex_unlock(&iph->iph_lock);
909 911
910 912 if (door_call(iph->iph_door_fd, &darg) == -1) {
911 913 /*
912 914 * Stale door descriptor is possible if ipmgmtd was restarted
913 915 * since last iph_door_fd was opened, so try re-opening door
914 916 * descriptor.
915 917 */
916 918 if (!reopen && errno == EBADF) {
917 919 (void) close(iph->iph_door_fd);
918 920 iph->iph_door_fd = -1;
919 921 reopen = B_TRUE;
920 922 goto reopen;
921 923 }
922 924 return (errno);
923 925 }
924 926 err = ((ipmgmt_retval_t *)(void *)(darg.rbuf))->ir_err;
925 927 if (darg.rbuf != *rbufp) {
926 928 /*
927 929 * if the caller is expecting the result to fit in specified
928 930 * buffer then return failure.
929 931 */
930 932 if (!is_varsize)
931 933 err = EBADE;
932 934 /*
933 935 * The size of the buffer `*rbufp' was not big enough
934 936 * and the door itself allocated buffer, for us. We will
935 937 * hit this, on several occasion as for some cases
936 938 * we cannot predict the size of the return structure.
937 939 * Reallocate the buffer `*rbufp' and memcpy() the contents
938 940 * to new buffer.
939 941 */
940 942 if (err == 0) {
941 943 void *newp;
942 944
943 945 /* allocated memory will be freed by the caller */
944 946 if ((newp = realloc(*rbufp, darg.rsize)) == NULL) {
945 947 err = ENOMEM;
946 948 } else {
947 949 *rbufp = newp;
|
↓ open down ↓ |
201 lines elided |
↑ open up ↑ |
948 950 (void) memcpy(*rbufp, darg.rbuf, darg.rsize);
949 951 }
950 952 }
951 953 /* munmap() the door buffer */
952 954 (void) munmap(darg.rbuf, darg.rsize);
953 955 } else {
954 956 if (darg.rsize != rsize)
955 957 err = EBADE;
956 958 }
957 959 return (err);
960 +}
961 +
962 +/*
963 + * ipadm_is_nil_hostname() : Determine if the `hostname' is nil: i.e.,
964 + * NULL, empty, or a single space (e.g., as returned by
965 + * domainname(1M)/sysinfo).
966 + *
967 + * input: const char *: the hostname to inspect;
968 + * output: boolean_t: B_TRUE if `hostname' is not NULL satisfies the
969 + * criteria above; otherwise, B_FALSE;
970 + */
971 +
972 +boolean_t
973 +ipadm_is_nil_hostname(const char *hostname)
974 +{
975 + return (hostname == NULL || *hostname == '\0'
976 + || (*hostname == ' ' && hostname[1] == '\0'));
977 +}
978 +
979 +/*
980 + * ipadm_is_valid_hostname(): check whether a string is a valid hostname
981 + *
982 + * input: const char *: the string to verify as a hostname
983 + * output: boolean_t: B_TRUE if the string is a valid hostname
984 + *
985 + * Note that we accept host names beginning with a digit, which is not
986 + * strictly legal according to the RFCs but is in common practice, so we
987 + * endeavour to not break what customers are using.
988 + *
989 + * RFC 1035 limits a wire-format domain name to 255 octets. For a printable
990 + * `hostname' as we have, the limit is therefore 253 characters (excluding
991 + * the terminating '\0'--or 254 characters if the last character of
992 + * `hostname' is a '.'.
993 + *
994 + * Excerpt from section 2.3.1., Preferred name syntax:
995 + *
996 + * <domain> ::= <subdomain> | " "
997 + * <subdomain> ::= <label> | <subdomain> "." <label>
998 + * <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
999 + * <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
1000 + * <let-dig-hyp> ::= <let-dig> | "-"
1001 + * <let-dig> ::= <letter> | <digit>
1002 + */
1003 +boolean_t
1004 +ipadm_is_valid_hostname(const char *hostname)
1005 +{
1006 + const size_t MAX_READABLE_NAME_LEN = 253;
1007 + char last_char;
1008 + size_t has_last_dot, namelen, i;
1009 +
1010 + if (hostname == NULL)
1011 + return B_FALSE;
1012 +
1013 + namelen = strlen(hostname);
1014 + if (namelen < 1)
1015 + return B_FALSE;
1016 +
1017 + last_char = hostname[namelen - 1];
1018 + has_last_dot = last_char == '.';
1019 +
1020 + if (namelen > MAX_READABLE_NAME_LEN + has_last_dot
1021 + || last_char == '-')
1022 + return B_FALSE;
1023 +
1024 + for (i = 0; hostname[i] != '\0'; i++) {
1025 + /*
1026 + * As noted above, this deviates from RFC 1035 in that it allows a
1027 + * leading digit.
1028 + */
1029 + if (isalpha(hostname[i]) || isdigit(hostname[i]) ||
1030 + (((hostname[i] == '-') || (hostname[i] == '.')) && (i > 0)))
1031 + continue;
1032 +
1033 + return (B_FALSE);
1034 + }
1035 +
1036 + return B_TRUE;
958 1037 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX