1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2016 by Delphix. All rights reserved. 25 */ 26 27 #include <stdlib.h> 28 #include <strings.h> 29 #include <stddef.h> 30 #include <sys/types.h> 31 #include <sys/socket.h> 32 #include <sys/list.h> 33 #include <assert.h> 34 #include <errno.h> 35 #include <libilb.h> 36 #include <net/if.h> 37 #include <inet/ilb.h> 38 #include <netinet/in.h> 39 #include <arpa/inet.h> 40 #include "libilb_impl.h" 41 #include "ilbd.h" 42 43 typedef enum { 44 not_searched, 45 stop_found, 46 cont_search, 47 fail_search 48 } srch_ind_t; 49 50 static list_t ilbd_sg_hlist; 51 52 static ilb_status_t i_delete_srv(ilbd_sg_t *, ilbd_srv_t *, int); 53 static void i_ilbd_free_srvID(ilbd_sg_t *, int32_t); 54 55 /* Last parameter to pass to i_find_srv(), specifying the matching mode */ 56 #define MODE_ADDR 1 57 #define MODE_SRVID 2 58 59 static ilbd_srv_t *i_find_srv(list_t *, ilb_sg_srv_t *, int); 60 61 void 62 i_setup_sg_hlist(void) 63 { 64 list_create(&ilbd_sg_hlist, sizeof (ilbd_sg_t), 65 offsetof(ilbd_sg_t, isg_link)); 66 } 67 68 /* 69 * allocate storage for a daemon-internal server group, init counters 70 */ 71 static ilbd_sg_t * 72 i_ilbd_alloc_sg(char *name) 73 { 74 ilbd_sg_t *d_sg; 75 76 d_sg = calloc(sizeof (*d_sg), 1); 77 if (d_sg == NULL) 78 goto out; 79 80 (void) strlcpy(d_sg->isg_name, name, sizeof (d_sg->isg_name)); 81 82 list_create(&d_sg->isg_srvlist, sizeof (ilbd_srv_t), 83 offsetof(ilbd_srv_t, isv_srv_link)); 84 list_create(&d_sg->isg_rulelist, sizeof (ilbd_rule_t), 85 offsetof(ilbd_rule_t, irl_sglink)); 86 87 list_insert_tail(&ilbd_sg_hlist, d_sg); 88 out: 89 return (d_sg); 90 } 91 92 static ilb_status_t 93 i_ilbd_save_sg(ilbd_sg_t *d_sg, ilbd_scf_cmd_t scf_cmd, const char *prop_name, 94 char *valstr) 95 { 96 switch (scf_cmd) { 97 case ILBD_SCF_CREATE: 98 return (ilbd_create_pg(ILBD_SCF_SG, (void *)d_sg)); 99 case ILBD_SCF_DESTROY: 100 return (ilbd_destroy_pg(ILBD_SCF_SG, d_sg->isg_name)); 101 case ILBD_SCF_ENABLE_DISABLE: 102 if (prop_name == NULL) 103 return (ILB_STATUS_EINVAL); 104 return (ilbd_change_prop(ILBD_SCF_SG, d_sg->isg_name, 105 prop_name, valstr)); 106 default: 107 logdebug("i_ilbd_save_sg: invalid scf cmd %d", scf_cmd); 108 return (ILB_STATUS_EINVAL); 109 } 110 } 111 112 ilb_status_t 113 i_attach_rule2sg(ilbd_sg_t *sg, ilbd_rule_t *irl) 114 { 115 /* assert: the same rule is attached to any sg only once */ 116 list_insert_tail(&sg->isg_rulelist, irl); 117 return (ILB_STATUS_OK); 118 } 119 120 static void 121 i_ilbd_free_sg(ilbd_sg_t *sg) 122 { 123 ilbd_srv_t *tmp_srv; 124 125 if (sg == NULL) 126 return; 127 list_remove(&ilbd_sg_hlist, sg); 128 while ((tmp_srv = list_remove_tail(&sg->isg_srvlist)) != NULL) { 129 i_ilbd_free_srvID(sg, tmp_srv->isv_id); 130 free(tmp_srv); 131 sg->isg_srvcount--; 132 } 133 free(sg); 134 } 135 136 ilbd_sg_t * 137 i_find_sg_byname(const char *name) 138 { 139 ilbd_sg_t *sg; 140 141 /* find position of sg in list */ 142 for (sg = list_head(&ilbd_sg_hlist); sg != NULL; 143 sg = list_next(&ilbd_sg_hlist, sg)) { 144 if (strncmp(sg->isg_name, name, sizeof (sg->isg_name)) == 0) 145 return (sg); 146 } 147 return (sg); 148 } 149 150 /* 151 * Generates an audit record for enable-server, disable-server, remove-server 152 * delete-servergroup, create-servergroup and add-server subcommands. 153 */ 154 static void 155 ilbd_audit_server_event(audit_sg_event_data_t *data, 156 ilbd_cmd_t cmd, ilb_status_t rc, ucred_t *ucredp) 157 { 158 adt_session_data_t *ah; 159 adt_event_data_t *event; 160 au_event_t flag; 161 int audit_error; 162 163 if ((ucredp == NULL) && ((cmd == ILBD_ADD_SERVER_TO_GROUP) || 164 (cmd == ILBD_CREATE_SERVERGROUP))) { 165 /* 166 * We came here from the path where ilbd is 167 * incorporating the ILB configuration from 168 * SCF. In that case, we skip auditing 169 */ 170 return; 171 } 172 173 if (adt_start_session(&ah, NULL, 0) != 0) { 174 logerr("ilbd_audit_server_event: adt_start_session failed"); 175 exit(EXIT_FAILURE); 176 } 177 178 if (adt_set_from_ucred(ah, ucredp, ADT_NEW) != 0) { 179 (void) adt_end_session(ah); 180 logerr("ilbd_audit_server_event: adt_set_from_ucred failed"); 181 exit(EXIT_FAILURE); 182 } 183 184 if (cmd == ILBD_ENABLE_SERVER) 185 flag = ADT_ilb_enable_server; 186 else if (cmd == ILBD_DISABLE_SERVER) 187 flag = ADT_ilb_disable_server; 188 else if (cmd == ILBD_REM_SERVER_FROM_GROUP) 189 flag = ADT_ilb_remove_server; 190 else if (cmd == ILBD_ADD_SERVER_TO_GROUP) 191 flag = ADT_ilb_add_server; 192 else if (cmd == ILBD_CREATE_SERVERGROUP) 193 flag = ADT_ilb_create_servergroup; 194 else if (cmd == ILBD_DESTROY_SERVERGROUP) 195 flag = ADT_ilb_delete_servergroup; 196 197 if ((event = adt_alloc_event(ah, flag)) == NULL) { 198 logerr("ilbd_audit_server_event: adt_alloc_event failed"); 199 exit(EXIT_FAILURE); 200 } 201 (void) memset((char *)event, 0, sizeof (adt_event_data_t)); 202 203 switch (cmd) { 204 case ILBD_ENABLE_SERVER: 205 event->adt_ilb_enable_server.auth_used = 206 NET_ILB_ENABLE_AUTH; 207 event->adt_ilb_enable_server.server_id = 208 data->ed_serverid; 209 event->adt_ilb_enable_server.server_ipaddress_type = 210 data->ed_ipaddr_type; 211 (void) memcpy(event->adt_ilb_enable_server.server_ipaddress, 212 data->ed_server_address, 213 (sizeof (data->ed_server_address))); 214 break; 215 case ILBD_DISABLE_SERVER: 216 event->adt_ilb_disable_server.auth_used = 217 NET_ILB_ENABLE_AUTH; 218 event->adt_ilb_disable_server.server_id = 219 data->ed_serverid; 220 event->adt_ilb_disable_server.server_ipaddress_type = 221 data->ed_ipaddr_type; 222 (void) memcpy(event->adt_ilb_disable_server.server_ipaddress, 223 data->ed_server_address, 224 (sizeof (data->ed_server_address))); 225 break; 226 case ILBD_REM_SERVER_FROM_GROUP: 227 event->adt_ilb_remove_server.auth_used = 228 NET_ILB_CONFIG_AUTH; 229 event->adt_ilb_remove_server.server_id = 230 data->ed_serverid; 231 event->adt_ilb_remove_server.server_group = data->ed_sgroup; 232 event->adt_ilb_remove_server.server_ipaddress_type = 233 data->ed_ipaddr_type; 234 (void) memcpy(event->adt_ilb_remove_server.server_ipaddress, 235 data->ed_server_address, 236 (sizeof (data->ed_server_address))); 237 break; 238 case ILBD_CREATE_SERVERGROUP: 239 event->adt_ilb_create_servergroup.auth_used = 240 NET_ILB_CONFIG_AUTH; 241 event->adt_ilb_create_servergroup.server_group = 242 data->ed_sgroup; 243 break; 244 case ILBD_ADD_SERVER_TO_GROUP: 245 event->adt_ilb_add_server.auth_used = 246 NET_ILB_CONFIG_AUTH; 247 event->adt_ilb_add_server.server_ipaddress_type = 248 data->ed_ipaddr_type; 249 (void) memcpy(event->adt_ilb_add_server.server_ipaddress, 250 data->ed_server_address, 251 (sizeof (data->ed_server_address))); 252 event->adt_ilb_add_server.server_id = 253 data->ed_serverid; 254 event->adt_ilb_add_server.server_group = 255 data->ed_sgroup; 256 event->adt_ilb_add_server.server_minport = 257 ntohs(data->ed_minport); 258 event->adt_ilb_add_server.server_maxport = 259 ntohs(data->ed_maxport); 260 break; 261 case ILBD_DESTROY_SERVERGROUP: 262 event->adt_ilb_delete_servergroup.auth_used = 263 NET_ILB_CONFIG_AUTH; 264 event->adt_ilb_delete_servergroup.server_group = 265 data->ed_sgroup; 266 break; 267 } 268 269 /* Fill in success/failure */ 270 if (rc == ILB_STATUS_OK) { 271 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 272 logerr("ilbd_audit_server_event:" 273 " adt_put_event failed"); 274 exit(EXIT_FAILURE); 275 } 276 } else { 277 audit_error = ilberror2auditerror(rc); 278 if (adt_put_event(event, ADT_FAILURE, audit_error) != 0) { 279 logerr("ilbd_audit_server_event:" 280 " adt_put_event failed"); 281 exit(EXIT_FAILURE); 282 } 283 } 284 adt_free_event(event); 285 (void) adt_end_session(ah); 286 } 287 288 ilb_status_t 289 ilbd_destroy_sg(const char *sg_name, const struct passwd *ps, 290 ucred_t *ucredp) 291 { 292 ilb_status_t rc; 293 ilbd_sg_t *tmp_sg; 294 audit_sg_event_data_t audit_sg_data; 295 296 (void) memset(&audit_sg_data, 0, sizeof (audit_sg_event_data_t)); 297 audit_sg_data.ed_sgroup = (char *)sg_name; 298 299 rc = ilbd_check_client_config_auth(ps); 300 if (rc != ILB_STATUS_OK) { 301 ilbd_audit_server_event(&audit_sg_data, 302 ILBD_DESTROY_SERVERGROUP, rc, ucredp); 303 return (rc); 304 } 305 306 tmp_sg = i_find_sg_byname(sg_name); 307 if (tmp_sg == NULL) { 308 logdebug("ilbd_destroy_sg: cannot find specified server" 309 " group %s", sg_name); 310 ilbd_audit_server_event(&audit_sg_data, 311 ILBD_DESTROY_SERVERGROUP, ILB_STATUS_SGUNAVAIL, ucredp); 312 return (ILB_STATUS_SGUNAVAIL); 313 } 314 315 /* 316 * we only destroy SGs that don't have any rules associated with 317 * them anymore. 318 */ 319 if (list_head(&tmp_sg->isg_rulelist) != NULL) { 320 logdebug("ilbd_destroy_sg: server group %s has rules" 321 " associated with it and thus cannot be" 322 " removed", tmp_sg->isg_name); 323 ilbd_audit_server_event(&audit_sg_data, 324 ILBD_DESTROY_SERVERGROUP, ILB_STATUS_SGINUSE, ucredp); 325 return (ILB_STATUS_SGINUSE); 326 } 327 328 if (ps != NULL) { 329 rc = i_ilbd_save_sg(tmp_sg, ILBD_SCF_DESTROY, NULL, NULL); 330 if (rc != ILB_STATUS_OK) { 331 ilbd_audit_server_event(&audit_sg_data, 332 ILBD_DESTROY_SERVERGROUP, rc, ucredp); 333 return (rc); 334 } 335 } 336 i_ilbd_free_sg(tmp_sg); 337 ilbd_audit_server_event(&audit_sg_data, ILBD_DESTROY_SERVERGROUP, 338 rc, ucredp); 339 return (rc); 340 } 341 342 /* ARGSUSED */ 343 /* 344 * Parameter ev_port is not used but has to have for read persistent configure 345 * ilbd_create_sg(), ilbd_create_hc() and ilbd_create_rule() are callbacks 346 * for ilbd_scf_instance_walk_pg() which requires the same signature. 347 */ 348 ilb_status_t 349 ilbd_create_sg(ilb_sg_info_t *sg, int ev_port, const struct passwd *ps, 350 ucred_t *ucredp) 351 { 352 ilb_status_t rc = ILB_STATUS_OK; 353 ilbd_sg_t *d_sg; 354 audit_sg_event_data_t audit_sg_data; 355 356 (void) memset(&audit_sg_data, 0, sizeof (audit_sg_event_data_t)); 357 audit_sg_data.ed_sgroup = sg->sg_name; 358 359 if (ps != NULL) { 360 rc = ilbd_check_client_config_auth(ps); 361 if (rc != ILB_STATUS_OK) { 362 ilbd_audit_server_event(&audit_sg_data, 363 ILBD_CREATE_SERVERGROUP, rc, ucredp); 364 return (rc); 365 } 366 } 367 368 if (i_find_sg_byname(sg->sg_name) != NULL) { 369 logdebug("ilbd_create_sg: server group %s already exists", 370 sg->sg_name); 371 ilbd_audit_server_event(&audit_sg_data, 372 ILBD_CREATE_SERVERGROUP, ILB_STATUS_SGEXISTS, ucredp); 373 return (ILB_STATUS_SGEXISTS); 374 } 375 376 d_sg = i_ilbd_alloc_sg(sg->sg_name); 377 if (d_sg == NULL) { 378 ilbd_audit_server_event(&audit_sg_data, 379 ILBD_CREATE_SERVERGROUP, ILB_STATUS_ENOMEM, ucredp); 380 return (ILB_STATUS_ENOMEM); 381 } 382 383 /* 384 * we've successfully created the sg in memory. Before we can 385 * return "success", we need to reflect this in persistent 386 * storage 387 */ 388 if (ps != NULL) { 389 rc = i_ilbd_save_sg(d_sg, ILBD_SCF_CREATE, NULL, NULL); 390 if (rc != ILB_STATUS_OK) { 391 i_ilbd_free_sg(d_sg); 392 ilbd_audit_server_event(&audit_sg_data, 393 ILBD_CREATE_SERVERGROUP, rc, ucredp); 394 return (rc); 395 } 396 } 397 ilbd_audit_server_event(&audit_sg_data, 398 ILBD_CREATE_SERVERGROUP, rc, ucredp); 399 return (rc); 400 } 401 402 /* 403 * This function checks whether tsrv should/can be inserted before lsrv 404 * and does so if possible. 405 * We keep the list in sorted order so we don't have to search it 406 * in its entirety for overlap every time we insert a new server. 407 * Return code: 408 * stop_found: don't continue searching because we found a place 409 * cont_search: continue with next element in the list 410 * fail_search: search failed (caller translates to ILB_STATUS_EEXIST) 411 */ 412 static srch_ind_t 413 i_test_and_insert(ilbd_srv_t *tsrv, ilbd_srv_t *lsrv, list_t *srvlist) 414 { 415 struct in6_addr *t1, *l1; 416 int fnd; 417 418 t1 = &tsrv->isv_addr; 419 l1 = &lsrv->isv_addr; 420 421 if ((fnd = ilb_cmp_in6_addr(t1, l1, NULL)) == 1) 422 return (cont_search); /* search can continue */ 423 424 if (fnd == 0) { 425 logdebug("i_test_and_insert: specified server already exists"); 426 return (fail_search); 427 } 428 /* the list is kept in ascending order */ 429 list_insert_before(srvlist, lsrv, tsrv); 430 return (stop_found); 431 } 432 433 434 /* 435 * copy a server description [ip1,ip2,port1,port2,srvID,flags] 436 */ 437 #define COPY_SERVER(src, dest) \ 438 (dest)->sgs_addr = (src)->sgs_addr; \ 439 (dest)->sgs_minport = (src)->sgs_minport; \ 440 (dest)->sgs_maxport = (src)->sgs_maxport; \ 441 (dest)->sgs_id = (src)->sgs_id; \ 442 (void) strlcpy((dest)->sgs_srvID, (src)->sgs_srvID, \ 443 sizeof ((dest)->sgs_srvID)); \ 444 (dest)->sgs_flags = (src)->sgs_flags 445 446 static ilb_status_t 447 i_add_srv2sg(ilbd_sg_t *dsg, ilb_sg_srv_t *srv, ilbd_srv_t **ret_srv) 448 { 449 ilb_sg_srv_t *n_sg_srv; 450 list_t *srvlist; 451 srch_ind_t search = not_searched; 452 ilb_status_t rc = ILB_STATUS_OK; 453 ilbd_srv_t *nsrv, *lsrv; 454 in_port_t h_minport, h_maxport; 455 456 nsrv = calloc(sizeof (*nsrv), 1); 457 if (nsrv == NULL) 458 return (ILB_STATUS_ENOMEM); 459 n_sg_srv = &nsrv->isv_srv; 460 COPY_SERVER(srv, n_sg_srv); 461 462 /* 463 * port info is in network byte order - we need host byte order 464 * for comparisons purposes 465 */ 466 h_minport = ntohs(n_sg_srv->sgs_minport); 467 h_maxport = ntohs(n_sg_srv->sgs_maxport); 468 if (h_minport != 0 && h_minport > h_maxport) 469 n_sg_srv->sgs_maxport = n_sg_srv->sgs_minport; 470 471 srvlist = &dsg->isg_srvlist; 472 473 lsrv = list_head(srvlist); 474 if (lsrv == NULL) { 475 list_insert_head(srvlist, nsrv); 476 } else { 477 while (lsrv != NULL) { 478 search = i_test_and_insert(nsrv, lsrv, 479 srvlist); 480 481 if (search != cont_search) 482 break; 483 lsrv = list_next(srvlist, lsrv); 484 485 /* if reaches the end of list, insert to the tail */ 486 if (search == cont_search && lsrv == NULL) 487 list_insert_tail(srvlist, nsrv); 488 } 489 if (search == fail_search) 490 rc = ILB_STATUS_EEXIST; 491 } 492 493 if (rc == ILB_STATUS_OK) { 494 dsg->isg_srvcount++; 495 *ret_srv = nsrv; 496 } else { 497 free(nsrv); 498 } 499 500 return (rc); 501 } 502 503 /* 504 * Allocate a server ID. The algorithm is simple. Just check the ID array 505 * of the server group and find an unused ID. If *set_id is given, it 506 * means that the ID is already allocated and the ID array needs to be 507 * updated. This is the case when ilbd reads from the persistent 508 * configuration. 509 */ 510 static int32_t 511 i_ilbd_alloc_srvID(ilbd_sg_t *sg, int32_t *set_id) 512 { 513 int32_t id; 514 int32_t i; 515 516 /* The server ID is already allocated, just update the ID array. */ 517 if (set_id != NULL) { 518 assert(sg->isg_id_arr[*set_id] == 0); 519 sg->isg_id_arr[*set_id] = 1; 520 return (*set_id); 521 } 522 523 /* if we're "full up", give back something invalid */ 524 if (sg->isg_srvcount == MAX_SRVCOUNT) 525 return (BAD_SRVID); 526 527 i = sg->isg_max_id; 528 for (id = 0; id < MAX_SRVCOUNT; id++) { 529 if (sg->isg_id_arr[(id + i) % MAX_SRVCOUNT] == 0) 530 break; 531 } 532 533 sg->isg_max_id = (id + i) % MAX_SRVCOUNT; 534 sg->isg_id_arr[sg->isg_max_id] = 1; 535 return (sg->isg_max_id); 536 } 537 538 /* 539 * Free a server ID by updating the server group's ID array. 540 */ 541 static void 542 i_ilbd_free_srvID(ilbd_sg_t *sg, int32_t id) 543 { 544 assert(sg->isg_id_arr[id] == 1); 545 sg->isg_id_arr[id] = 0; 546 } 547 548 /* 549 * This function is called by ilbd_add_server_to_group() and 550 * ilb_remove_server_group() to create a audit record for a 551 * failed servicing of add-server/remove-server command 552 */ 553 static void 554 fill_audit_record(ilb_sg_info_t *sg, audit_sg_event_data_t *audit_sg_data, 555 ilbd_cmd_t cmd, ilb_status_t rc, ucred_t *ucredp) 556 { 557 ilb_sg_srv_t *tsrv; 558 int i; 559 560 for (i = 0; i < sg->sg_srvcount; i++) { 561 tsrv = &sg->sg_servers[i]; 562 if (cmd == ILBD_ADD_SERVER_TO_GROUP) { 563 564 audit_sg_data->ed_serverid = NULL; 565 if (IN6_IS_ADDR_V4MAPPED(&tsrv->sgs_addr)) { 566 audit_sg_data->ed_ipaddr_type = ADT_IPv4; 567 cvt_addr(audit_sg_data->ed_server_address, 568 ADT_IPv4, tsrv->sgs_addr); 569 } else { 570 audit_sg_data->ed_ipaddr_type = ADT_IPv6; 571 cvt_addr(audit_sg_data->ed_server_address, 572 ADT_IPv6, tsrv->sgs_addr); 573 } 574 audit_sg_data->ed_minport = tsrv->sgs_minport; 575 audit_sg_data->ed_maxport = tsrv->sgs_maxport; 576 audit_sg_data->ed_sgroup = sg->sg_name; 577 } else if (cmd == ILBD_REM_SERVER_FROM_GROUP) { 578 audit_sg_data->ed_serverid = tsrv->sgs_srvID; 579 audit_sg_data->ed_sgroup = sg->sg_name; 580 581 audit_sg_data->ed_minport = 0; 582 audit_sg_data->ed_maxport = 0; 583 } 584 ilbd_audit_server_event(audit_sg_data, cmd, rc, ucredp); 585 } 586 } 587 588 /* 589 * the name(s) of the server(s) are encoded in the sg. 590 */ 591 ilb_status_t 592 ilbd_add_server_to_group(ilb_sg_info_t *sg_info, int ev_port, 593 const struct passwd *ps, ucred_t *ucredp) 594 { 595 ilb_status_t rc = ILB_STATUS_OK; 596 ilbd_sg_t *tmp_sg; 597 int i, j; 598 int32_t new_id = BAD_SRVID; 599 int32_t af = AF_UNSPEC; 600 ilbd_srv_t *nsrv; 601 ilb_sg_srv_t *srv; 602 audit_sg_event_data_t audit_sg_data; 603 604 if (ps != NULL) { 605 rc = ilbd_check_client_config_auth(ps); 606 if (rc != ILB_STATUS_OK) { 607 fill_audit_record(sg_info, &audit_sg_data, 608 ILBD_ADD_SERVER_TO_GROUP, rc, ucredp); 609 return (rc); 610 } 611 } 612 613 tmp_sg = i_find_sg_byname(sg_info->sg_name); 614 if (tmp_sg == NULL) { 615 logdebug("ilbd_add_server_to_group: server" 616 " group %s does not exist", sg_info->sg_name); 617 fill_audit_record(sg_info, &audit_sg_data, 618 ILBD_ADD_SERVER_TO_GROUP, ILB_STATUS_ENOENT, ucredp); 619 return (ILB_STATUS_ENOENT); 620 } 621 622 /* 623 * we do the dance with address family below to make sure only 624 * IP addresses in the same AF get into an SG; the first one to get 625 * in sets the "tone" 626 * if this is the first server to join a group, check whether 627 * there's no mismatch with any *rules* already attached 628 */ 629 if (tmp_sg->isg_srvcount > 0) { 630 ilbd_srv_t *tsrv = list_head(&tmp_sg->isg_srvlist); 631 632 af = GET_AF(&tsrv->isv_addr); 633 } else { 634 ilbd_rule_t *irl = list_head(&tmp_sg->isg_rulelist); 635 636 if (irl != NULL) 637 af = GET_AF(&irl->irl_vip); 638 } 639 640 for (i = 0; i < sg_info->sg_srvcount; i++) { 641 srv = &sg_info->sg_servers[i]; 642 643 (void) memset(&audit_sg_data, 0, sizeof (audit_sg_data)); 644 if (IN6_IS_ADDR_V4MAPPED(&srv->sgs_addr)) { 645 audit_sg_data.ed_ipaddr_type = ADT_IPv4; 646 cvt_addr(audit_sg_data.ed_server_address, ADT_IPv4, 647 srv->sgs_addr); 648 } else { 649 audit_sg_data.ed_ipaddr_type = ADT_IPv6; 650 cvt_addr(audit_sg_data.ed_server_address, ADT_IPv6, 651 srv->sgs_addr); 652 } 653 audit_sg_data.ed_minport = srv->sgs_minport; 654 audit_sg_data.ed_maxport = srv->sgs_maxport; 655 audit_sg_data.ed_sgroup = sg_info->sg_name; 656 657 /* only test if we have sth to test against */ 658 if (af != AF_UNSPEC) { 659 int32_t sgs_af = GET_AF(&srv->sgs_addr); 660 661 if (af != sgs_af) { 662 logdebug("address family mismatch with previous" 663 " hosts in servergroup or with rule"); 664 rc = ILB_STATUS_MISMATCHH; 665 ilbd_audit_server_event(&audit_sg_data, 666 ILBD_ADD_SERVER_TO_GROUP, rc, ucredp); 667 goto rollback; 668 } 669 } 670 671 /* 672 * PS: NULL means daemon is loading configure from scf. 673 * ServerID is already assigned, just update the ID array. 674 */ 675 if (ps != NULL) { 676 new_id = i_ilbd_alloc_srvID(tmp_sg, NULL); 677 if (new_id == BAD_SRVID) { 678 logdebug("ilbd_add_server_to_group: server" 679 "group %s is full, no more servers" 680 " can be added", sg_info->sg_name); 681 rc = ILB_STATUS_SGFULL; 682 ilbd_audit_server_event(&audit_sg_data, 683 ILBD_ADD_SERVER_TO_GROUP, rc, ucredp); 684 goto rollback; 685 } 686 srv->sgs_id = new_id; 687 } else { 688 new_id = i_ilbd_alloc_srvID(tmp_sg, &srv->sgs_id); 689 } 690 691 /* 692 * here we implement the requirement that server IDs start 693 * with a character that is not legal in hostnames - in our 694 * case, a "_" (underscore). 695 */ 696 (void) snprintf(srv->sgs_srvID, 697 sizeof (srv->sgs_srvID), "%c%s.%d", ILB_SRVID_PREFIX, 698 tmp_sg->isg_name, srv->sgs_id); 699 audit_sg_data.ed_serverid = srv->sgs_srvID; 700 701 /* 702 * Before we update the kernel rules by adding the server, 703 * we need to make checks and fail if any of the 704 * following is true: 705 * 706 * o if the server has single port and the servergroup 707 * is associated to a DSR rule with a port range 708 * o if the server has a port range and the servergroup 709 * is associated to a DSR rule with a port range and 710 * the rule's min and max port does not exactly 711 * match that of the server's. 712 * o if the the server has a port range and the servergroup 713 * is associated to a NAT/Half-NAT rule with a port range 714 * and the rule's port range size does not match that 715 * of the server's. 716 * o if the rule has a fixed hc port, check that this port 717 * is valid in the server's port specification. 718 */ 719 rc = i_check_srv2rules(&tmp_sg->isg_rulelist, srv); 720 if (rc != ILB_STATUS_OK) { 721 ilbd_audit_server_event(&audit_sg_data, 722 ILBD_ADD_SERVER_TO_GROUP, rc, ucredp); 723 goto rollback; 724 } 725 726 if ((rc = i_add_srv2sg(tmp_sg, srv, &nsrv)) != ILB_STATUS_OK) { 727 ilbd_audit_server_event(&audit_sg_data, 728 ILBD_ADD_SERVER_TO_GROUP, rc, ucredp); 729 goto rollback; 730 } 731 732 rc = i_add_srv2krules(&tmp_sg->isg_rulelist, &nsrv->isv_srv, 733 ev_port); 734 if (rc != ILB_STATUS_OK) { 735 ilbd_audit_server_event(&audit_sg_data, 736 ILBD_ADD_SERVER_TO_GROUP, rc, ucredp); 737 /* 738 * The failure may be due to the serverid being on 739 * hold in kernel for connection draining. But ilbd 740 * has no way of knowing that. So we are freeing up 741 * the serverid, and may run into the risk of 742 * having this failure again, if we choose this 743 * serverid when processing the next add-server 744 * command for this servergroup, while connection 745 * draining is underway. We assume that the user 746 * will read the man page after they encounter 747 * this failure, and learn to not add any server 748 * to the servergroup until connection draining of 749 * all servers in the servergroup is complete. 750 * XXX Need to revisit this when connection draining 751 * is reworked 752 */ 753 list_remove(&tmp_sg->isg_srvlist, nsrv); 754 i_ilbd_free_srvID(tmp_sg, nsrv->isv_id); 755 free(nsrv); 756 tmp_sg->isg_srvcount--; 757 goto rollback; 758 } 759 if (ps != NULL) { 760 rc = ilbd_scf_add_srv(tmp_sg, nsrv); 761 if (rc != ILB_STATUS_OK) { 762 /* 763 * The following should not fail since the 764 * server is just added. Just in case, we 765 * pass in -1 as the event port to avoid 766 * roll back in i_rem_srv_frm_krules() called 767 * by i_delete_srv(). 768 */ 769 ilbd_audit_server_event(&audit_sg_data, 770 ILBD_ADD_SERVER_TO_GROUP, rc, ucredp); 771 (void) i_delete_srv(tmp_sg, nsrv, -1); 772 break; 773 } 774 } 775 } 776 777 if (rc == ILB_STATUS_OK) { 778 ilbd_audit_server_event(&audit_sg_data, 779 ILBD_ADD_SERVER_TO_GROUP, rc, ucredp); 780 return (rc); 781 } 782 783 rollback: 784 /* 785 * If ilbd is initializing based on the SCF data and something fails, 786 * the only choice is to transition the service to maintanence mode... 787 */ 788 if (ps == NULL) { 789 logerr("%s: failure during initialization -" 790 " entering maintenance mode", __func__); 791 (void) smf_maintain_instance(ILB_FMRI, SMF_IMMEDIATE); 792 return (rc); 793 } 794 795 /* 796 * we need to roll back all servers previous to the one 797 * that just caused the failure 798 */ 799 for (j = i-1; j >= 0; j--) { 800 srv = &sg_info->sg_servers[j]; 801 802 /* We should be able to find those servers just added. */ 803 nsrv = i_find_srv(&tmp_sg->isg_srvlist, srv, MODE_SRVID); 804 assert(nsrv != NULL); 805 (void) i_delete_srv(tmp_sg, nsrv, -1); 806 } 807 return (rc); 808 } 809 810 static srch_ind_t 811 i_match_srvID(ilb_sg_srv_t *sg_srv, ilbd_srv_t *lsrv) 812 { 813 if (strncmp(sg_srv->sgs_srvID, lsrv->isv_srvID, 814 sizeof (sg_srv->sgs_srvID)) == 0) { 815 return (stop_found); 816 } 817 return (cont_search); 818 } 819 820 /* 821 * Sanity check on a rule's port specification against all the servers' 822 * specification in its associated server group. 823 * 824 * 1. If the health check's probe port (hcport) is specified. 825 * - if server port range is specified, check if hcport is inside 826 * the range 827 * - if no server port is specified (meaning the port range is the same as 828 * the rule's port range), check if hcport is inside the rule's range. 829 * 830 * 2. If a server has no port specification, there is no conflict. 831 * 832 * 3. If the rule's load balance mode is DSR, a server port specification must 833 * be exactly the same as the rule's. 834 * 835 * 4. In other modes (NAT and half-NAT), the server's port range must be 836 * the same as the rule's, unless it is doing port collapsing (the server's 837 * port range is only 1). 838 */ 839 ilb_status_t 840 ilbd_sg_check_rule_port(ilbd_sg_t *sg, ilb_rule_info_t *rl) 841 { 842 ilbd_srv_t *srv; 843 in_port_t r_minport, r_maxport; 844 845 /* Don't allow adding a rule to a sg with no server, for now... */ 846 if (sg->isg_srvcount == 0) 847 return (ILB_STATUS_SGEMPTY); 848 849 r_minport = ntohs(rl->rl_minport); 850 r_maxport = ntohs(rl->rl_maxport); 851 852 for (srv = list_head(&sg->isg_srvlist); srv != NULL; 853 srv = list_next(&sg->isg_srvlist, srv)) { 854 in_port_t srv_minport, srv_maxport; 855 int range; 856 857 srv_minport = ntohs(srv->isv_minport); 858 srv_maxport = ntohs(srv->isv_maxport); 859 range = srv_maxport - srv_minport; 860 861 /* 862 * If the rule has a specific probe port, check if that port is 863 * valid in all the servers' port specification. 864 */ 865 if (rl->rl_hcpflag == ILB_HCI_PROBE_FIX) { 866 in_port_t hcport = ntohs(rl->rl_hcport); 867 868 /* No server port specified. */ 869 if (srv_minport == 0) { 870 if (hcport > r_maxport || hcport < r_minport) { 871 return (ILB_STATUS_BADSG); 872 } 873 } else { 874 if (hcport > srv_maxport || 875 hcport < srv_minport) { 876 return (ILB_STATUS_BADSG); 877 } 878 } 879 } 880 881 /* 882 * There is no server port specification, so there cannot be 883 * any conflict. 884 */ 885 if (srv_minport == 0) 886 continue; 887 888 if (rl->rl_topo == ILB_TOPO_DSR) { 889 if (r_minport != srv_minport || 890 r_maxport != srv_maxport) { 891 return (ILB_STATUS_BADSG); 892 } 893 } else { 894 if ((range != r_maxport - r_minport) && range != 0) 895 return (ILB_STATUS_BADSG); 896 } 897 } 898 899 return (ILB_STATUS_OK); 900 } 901 902 static srch_ind_t 903 i_match_srvIP(ilb_sg_srv_t *sg_srv, ilbd_srv_t *lsrv) 904 { 905 if (IN6_ARE_ADDR_EQUAL(&sg_srv->sgs_addr, &lsrv->isv_addr)) 906 return (stop_found); 907 return (cont_search); 908 } 909 910 static ilbd_srv_t * 911 i_find_srv(list_t *srvlist, ilb_sg_srv_t *sg_srv, int cmpmode) 912 { 913 ilbd_srv_t *tmp_srv; 914 srch_ind_t srch_res = cont_search; 915 916 for (tmp_srv = list_head(srvlist); tmp_srv != NULL; 917 tmp_srv = list_next(srvlist, tmp_srv)) { 918 switch (cmpmode) { 919 case MODE_ADDR: 920 srch_res = i_match_srvIP(sg_srv, tmp_srv); 921 break; 922 case MODE_SRVID: 923 srch_res = i_match_srvID(sg_srv, tmp_srv); 924 break; 925 } 926 if (srch_res == stop_found) 927 break; 928 } 929 930 if (srch_res == stop_found) 931 return (tmp_srv); 932 return (NULL); 933 } 934 935 static ilb_status_t 936 i_delete_srv(ilbd_sg_t *sg, ilbd_srv_t *srv, int ev_port) 937 { 938 ilb_status_t rc; 939 940 rc = i_rem_srv_frm_krules(&sg->isg_rulelist, &srv->isv_srv, ev_port); 941 if (rc != ILB_STATUS_OK) 942 return (rc); 943 list_remove(&sg->isg_srvlist, srv); 944 i_ilbd_free_srvID(sg, srv->isv_id); 945 free(srv); 946 sg->isg_srvcount--; 947 return (ILB_STATUS_OK); 948 } 949 950 /* 951 * some people argue that returning anything here is 952 * useless - what *do* you do if you can't remove/destroy 953 * something anyway? 954 */ 955 ilb_status_t 956 ilbd_rem_server_from_group(ilb_sg_info_t *sg_info, int ev_port, 957 const struct passwd *ps, ucred_t *ucredp) 958 { 959 ilb_status_t rc = ILB_STATUS_OK; 960 ilbd_sg_t *tmp_sg; 961 ilbd_srv_t *srv, tmp_srv; 962 ilb_sg_srv_t *tsrv; 963 audit_sg_event_data_t audit_sg_data; 964 965 rc = ilbd_check_client_config_auth(ps); 966 if (rc != ILB_STATUS_OK) { 967 fill_audit_record(sg_info, &audit_sg_data, 968 ILBD_REM_SERVER_FROM_GROUP, rc, ucredp); 969 return (rc); 970 } 971 972 tmp_sg = i_find_sg_byname(sg_info->sg_name); 973 if (tmp_sg == NULL) { 974 logdebug("%s: server group %s\n does not exist", __func__, 975 sg_info->sg_name); 976 fill_audit_record(sg_info, &audit_sg_data, 977 ILBD_REM_SERVER_FROM_GROUP, ILB_STATUS_SGUNAVAIL, ucredp); 978 return (ILB_STATUS_SGUNAVAIL); 979 } 980 tsrv = &sg_info->sg_servers[0]; 981 audit_sg_data.ed_serverid = tsrv->sgs_srvID; 982 audit_sg_data.ed_sgroup = sg_info->sg_name; 983 984 assert(sg_info->sg_srvcount == 1); 985 srv = i_find_srv(&tmp_sg->isg_srvlist, &sg_info->sg_servers[0], 986 MODE_SRVID); 987 if (srv == NULL) { 988 logdebug("%s: cannot find server in server group %s", __func__, 989 sg_info->sg_name); 990 ilbd_audit_server_event(&audit_sg_data, 991 ILBD_REM_SERVER_FROM_GROUP, ILB_STATUS_SRVUNAVAIL, ucredp); 992 return (ILB_STATUS_SRVUNAVAIL); 993 } 994 tsrv = &srv->isv_srv; 995 if (IN6_IS_ADDR_V4MAPPED(&tsrv->sgs_addr)) { 996 audit_sg_data.ed_ipaddr_type = ADT_IPv4; 997 cvt_addr(audit_sg_data.ed_server_address, ADT_IPv4, 998 tsrv->sgs_addr); 999 } else { 1000 audit_sg_data.ed_ipaddr_type = ADT_IPv6; 1001 cvt_addr(audit_sg_data.ed_server_address, ADT_IPv6, 1002 tsrv->sgs_addr); 1003 } 1004 /* 1005 * i_delete_srv frees srv, therefore we need to save 1006 * this information for ilbd_scf_del_srv 1007 */ 1008 (void) memcpy(&tmp_srv, srv, sizeof (tmp_srv)); 1009 1010 rc = i_delete_srv(tmp_sg, srv, ev_port); 1011 if (rc != ILB_STATUS_OK) { 1012 ilbd_audit_server_event(&audit_sg_data, 1013 ILBD_REM_SERVER_FROM_GROUP, rc, ucredp); 1014 return (rc); 1015 } 1016 1017 if (ps != NULL) { 1018 if ((rc = ilbd_scf_del_srv(tmp_sg, &tmp_srv)) != 1019 ILB_STATUS_OK) { 1020 ilbd_audit_server_event(&audit_sg_data, 1021 ILBD_REM_SERVER_FROM_GROUP, rc, ucredp); 1022 logerr("%s: SCF update failed - entering maintenance" 1023 " mode", __func__); 1024 (void) smf_maintain_instance(ILB_FMRI, SMF_IMMEDIATE); 1025 } 1026 } 1027 ilbd_audit_server_event(&audit_sg_data, 1028 ILBD_REM_SERVER_FROM_GROUP, rc, ucredp); 1029 return (rc); 1030 } 1031 1032 ilb_status_t 1033 ilbd_retrieve_names(ilbd_cmd_t cmd, uint32_t *rbuf, size_t *rbufsz) 1034 { 1035 ilb_status_t rc = ILB_STATUS_OK; 1036 ilbd_namelist_t *nlist; 1037 size_t tmp_rbufsz; 1038 1039 tmp_rbufsz = *rbufsz; 1040 /* Set up the reply buffer. rbufsz will be set to the new size. */ 1041 ilbd_reply_ok(rbuf, rbufsz); 1042 1043 /* Calculate how much space is left for holding name info. */ 1044 *rbufsz += sizeof (ilbd_namelist_t); 1045 tmp_rbufsz -= *rbufsz; 1046 1047 nlist = (ilbd_namelist_t *)&((ilb_comm_t *)rbuf)->ic_data; 1048 nlist->ilbl_count = 0; 1049 1050 switch (cmd) { 1051 case ILBD_RETRIEVE_SG_NAMES: { 1052 ilbd_sg_t *sg; 1053 1054 for (sg = list_head(&ilbd_sg_hlist); 1055 sg != NULL && tmp_rbufsz >= sizeof (ilbd_name_t); 1056 sg = list_next(&ilbd_sg_hlist, sg), 1057 tmp_rbufsz -= sizeof (ilbd_name_t)) { 1058 (void) strlcpy(nlist->ilbl_name[nlist->ilbl_count++], 1059 sg->isg_name, sizeof (ilbd_name_t)); 1060 } 1061 break; 1062 } 1063 case ILBD_RETRIEVE_RULE_NAMES: { 1064 ilbd_rule_t *irl; 1065 extern list_t ilbd_rule_hlist; 1066 1067 for (irl = list_head(&ilbd_rule_hlist); 1068 irl != NULL && tmp_rbufsz >= sizeof (ilbd_name_t); 1069 irl = list_next(&ilbd_rule_hlist, irl), 1070 tmp_rbufsz -= sizeof (ilbd_name_t)) { 1071 (void) strlcpy(nlist->ilbl_name[nlist->ilbl_count++], 1072 irl->irl_name, sizeof (ilbd_name_t)); 1073 } 1074 break; 1075 } 1076 case ILBD_RETRIEVE_HC_NAMES: { 1077 extern list_t ilbd_hc_list; 1078 ilbd_hc_t *hc; 1079 1080 for (hc = list_head(&ilbd_hc_list); 1081 hc != NULL && tmp_rbufsz >= sizeof (ilbd_name_t); 1082 hc = list_next(&ilbd_hc_list, hc)) { 1083 (void) strlcpy(nlist->ilbl_name[nlist->ilbl_count++], 1084 hc->ihc_name, sizeof (ilbd_name_t)); 1085 } 1086 break; 1087 } 1088 default: 1089 logdebug("ilbd_retrieve_names: unknown command"); 1090 return (ILB_STATUS_INVAL_CMD); 1091 } 1092 1093 *rbufsz += nlist->ilbl_count * sizeof (ilbd_name_t); 1094 return (rc); 1095 } 1096 1097 ilb_status_t 1098 ilbd_retrieve_sg_hosts(const char *sg_name, uint32_t *rbuf, size_t *rbufsz) 1099 { 1100 ilbd_sg_t *dsg; 1101 ilbd_srv_t *dsrv; 1102 list_t *srvlist; 1103 ilb_sg_info_t *sg_info; 1104 size_t tmp_rbufsz; 1105 1106 dsg = i_find_sg_byname(sg_name); 1107 if (dsg == NULL) { 1108 logdebug("ilbd_retrieve_sg_hosts: server group" 1109 " %s not found", sg_name); 1110 return (ILB_STATUS_SGUNAVAIL); 1111 } 1112 1113 srvlist = &dsg->isg_srvlist; 1114 dsrv = list_head(srvlist); 1115 1116 tmp_rbufsz = *rbufsz; 1117 ilbd_reply_ok(rbuf, rbufsz); 1118 1119 /* Calculate the size to hold all the hosts info. */ 1120 *rbufsz += sizeof (ilb_sg_info_t); 1121 tmp_rbufsz -= *rbufsz; 1122 1123 sg_info = (ilb_sg_info_t *)&((ilb_comm_t *)rbuf)->ic_data; 1124 (void) strlcpy(sg_info->sg_name, sg_name, sizeof (sg_info->sg_name)); 1125 sg_info->sg_srvcount = 0; 1126 1127 while (dsrv != NULL && tmp_rbufsz >= sizeof (ilb_sg_srv_t)) { 1128 sg_info->sg_servers[sg_info->sg_srvcount++] = dsrv->isv_srv; 1129 dsrv = list_next(srvlist, dsrv); 1130 tmp_rbufsz -= sizeof (ilb_sg_srv_t); 1131 } 1132 *rbufsz += sg_info->sg_srvcount * sizeof (ilb_sg_srv_t); 1133 return (ILB_STATUS_OK); 1134 } 1135 1136 /* 1137 * this mapping function works on the assumption that HC only is 1138 * active when a server is enabled. 1139 */ 1140 static ilb_cmd_t 1141 i_srvcmd_d2k(ilbd_srv_status_ind_t dcmd) 1142 { 1143 ilb_cmd_t cmd; 1144 1145 switch (dcmd) { 1146 case stat_enable_server: 1147 case stat_declare_srv_alive: 1148 cmd = ILB_ENABLE_SERVERS; 1149 break; 1150 case stat_disable_server: 1151 case stat_declare_srv_dead: 1152 cmd = ILB_DISABLE_SERVERS; 1153 break; 1154 } 1155 1156 return (cmd); 1157 } 1158 1159 ilb_status_t 1160 ilbd_k_Xable_server(const struct in6_addr *addr, const char *rlname, 1161 ilbd_srv_status_ind_t cmd) 1162 { 1163 ilb_status_t rc; 1164 ilb_servers_cmd_t kcmd; 1165 int e; 1166 1167 kcmd.cmd = i_srvcmd_d2k(cmd); 1168 (void) strlcpy(kcmd.name, rlname, sizeof (kcmd.name)); 1169 kcmd.num_servers = 1; 1170 1171 kcmd.servers[0].addr = *addr; 1172 kcmd.servers[0].err = 0; 1173 1174 rc = do_ioctl(&kcmd, 0); 1175 if (rc != ILB_STATUS_OK) 1176 return (rc); 1177 1178 if ((e = kcmd.servers[0].err) != 0) { 1179 logdebug("ilbd_k_Xable_server: error %s occurred", 1180 strerror(e)); 1181 return (ilb_map_errno2ilbstat(e)); 1182 } 1183 1184 return (rc); 1185 } 1186 1187 #define IS_SRV_ENABLED(s) ILB_IS_SRV_ENABLED((s)->sgs_flags) 1188 #define IS_SRV_DISABLED(s) (!(IS_SRV_ENABLED(s))) 1189 1190 #define SET_SRV_ENABLED(s) ILB_SET_ENABLED((s)->sgs_flags) 1191 #define SET_SRV_DISABLED(s) ILB_SET_DISABLED((s)->sgs_flags) 1192 1193 static ilb_status_t 1194 ilbd_Xable_server(ilb_sg_info_t *sg, const struct passwd *ps, 1195 ilbd_srv_status_ind_t cmd, ucred_t *ucredp) 1196 { 1197 ilb_status_t rc = ILB_STATUS_OK; 1198 ilbd_sg_t *isg; 1199 ilbd_srv_t *tmp_srv; 1200 ilb_sg_srv_t *srv; 1201 ilbd_rule_t *irl; 1202 char *dot; 1203 int scf_name_len = ILBD_MAX_NAME_LEN; 1204 int scf_val_len = ILBD_MAX_VALUE_LEN; 1205 char *prop_name = NULL; 1206 ilb_ip_addr_t ipaddr; 1207 void *addrptr; 1208 char ipstr[INET6_ADDRSTRLEN], *valstr = NULL; 1209 int ipver, vallen; 1210 char sgname[ILB_NAMESZ]; 1211 uint32_t nflags; 1212 ilbd_srv_status_ind_t u_cmd; 1213 audit_sg_event_data_t audit_sg_data; 1214 1215 (void) memset(&audit_sg_data, 0, sizeof (audit_sg_data)); 1216 1217 /* we currently only implement a "list" of one */ 1218 assert(sg->sg_srvcount == 1); 1219 1220 srv = &sg->sg_servers[0]; 1221 audit_sg_data.ed_serverid = srv->sgs_srvID; 1222 1223 rc = ilbd_check_client_enable_auth(ps); 1224 if (rc != ILB_STATUS_OK) { 1225 ilbd_audit_server_event(&audit_sg_data, 1226 ILBD_ENABLE_SERVER, rc, ucredp); 1227 return (rc); 1228 } 1229 1230 if (srv->sgs_srvID[0] != ILB_SRVID_PREFIX) { 1231 switch (cmd) { 1232 case stat_disable_server: 1233 ilbd_audit_server_event(&audit_sg_data, 1234 ILBD_DISABLE_SERVER, 1235 ILB_STATUS_EINVAL, ucredp); 1236 break; 1237 case stat_enable_server: 1238 ilbd_audit_server_event(&audit_sg_data, 1239 ILBD_ENABLE_SERVER, 1240 ILB_STATUS_EINVAL, ucredp); 1241 break; 1242 } 1243 return (ILB_STATUS_EINVAL); 1244 } 1245 1246 /* 1247 * the following asserts that serverIDs are constructed 1248 * along the pattern "_"<SG name>"."<number> 1249 * so we look for the final "." to recreate the SG name. 1250 */ 1251 (void) strlcpy(sgname, srv->sgs_srvID + 1, sizeof (sgname)); 1252 dot = strrchr(sgname, (int)'.'); 1253 if (dot == NULL) { 1254 switch (cmd) { 1255 case stat_disable_server: 1256 ilbd_audit_server_event(&audit_sg_data, 1257 ILBD_DISABLE_SERVER, 1258 ILB_STATUS_EINVAL, ucredp); 1259 break; 1260 case stat_enable_server: 1261 ilbd_audit_server_event(&audit_sg_data, 1262 ILBD_ENABLE_SERVER, 1263 ILB_STATUS_EINVAL, ucredp); 1264 break; 1265 } 1266 return (ILB_STATUS_EINVAL); 1267 } 1268 1269 /* make the non-sg_name part "invisible" */ 1270 *dot = '\0'; 1271 isg = i_find_sg_byname(sgname); 1272 if (isg == NULL) { 1273 switch (cmd) { 1274 case stat_disable_server: 1275 ilbd_audit_server_event(&audit_sg_data, 1276 ILBD_DISABLE_SERVER, 1277 ILB_STATUS_ENOENT, ucredp); 1278 break; 1279 case stat_enable_server: 1280 ilbd_audit_server_event(&audit_sg_data, 1281 ILBD_ENABLE_SERVER, 1282 ILB_STATUS_ENOENT, ucredp); 1283 break; 1284 } 1285 return (ILB_STATUS_ENOENT); 1286 } 1287 1288 tmp_srv = i_find_srv(&isg->isg_srvlist, srv, MODE_SRVID); 1289 if (tmp_srv == NULL) { 1290 switch (cmd) { 1291 case stat_disable_server: 1292 ilbd_audit_server_event(&audit_sg_data, 1293 ILBD_DISABLE_SERVER, 1294 ILB_STATUS_ENOENT, ucredp); 1295 break; 1296 case stat_enable_server: 1297 ilbd_audit_server_event(&audit_sg_data, 1298 ILBD_ENABLE_SERVER, 1299 ILB_STATUS_ENOENT, ucredp); 1300 break; 1301 } 1302 return (ILB_STATUS_ENOENT); 1303 } 1304 1305 /* 1306 * if server's servergroup is not associated with 1307 * a rule, do not enable it. 1308 */ 1309 irl = list_head(&isg->isg_rulelist); 1310 if (irl == NULL) { 1311 switch (cmd) { 1312 case stat_disable_server: 1313 ilbd_audit_server_event(&audit_sg_data, 1314 ILBD_DISABLE_SERVER, 1315 ILB_STATUS_INVAL_ENBSRVR, ucredp); 1316 break; 1317 case stat_enable_server: 1318 ilbd_audit_server_event(&audit_sg_data, 1319 ILBD_ENABLE_SERVER, 1320 ILB_STATUS_INVAL_ENBSRVR, ucredp); 1321 break; 1322 } 1323 return (ILB_STATUS_INVAL_ENBSRVR); 1324 } 1325 /* Fill in the server IP address for audit record */ 1326 if (IN6_IS_ADDR_V4MAPPED(&tmp_srv->isv_addr)) { 1327 audit_sg_data.ed_ipaddr_type = ADT_IPv4; 1328 cvt_addr(audit_sg_data.ed_server_address, ADT_IPv4, 1329 tmp_srv->isv_addr); 1330 } else { 1331 audit_sg_data.ed_ipaddr_type = ADT_IPv6; 1332 cvt_addr(audit_sg_data.ed_server_address, ADT_IPv6, 1333 tmp_srv->isv_addr); 1334 } 1335 1336 /* 1337 * We have found the server in memory, perform the following 1338 * tasks. 1339 * 1340 * 1. For every rule associated with this SG, 1341 * - tell the kernel 1342 * - tell the hc 1343 * 2. Update our internal state and persistent configuration 1344 * if the new state is not the same as the old one. 1345 */ 1346 /* 1. */ 1347 for (; irl != NULL; irl = list_next(&isg->isg_rulelist, irl)) { 1348 rc = ilbd_k_Xable_server(&tmp_srv->isv_addr, 1349 irl->irl_name, cmd); 1350 if (rc != ILB_STATUS_OK) { 1351 switch (cmd) { 1352 case stat_disable_server: 1353 ilbd_audit_server_event(&audit_sg_data, 1354 ILBD_DISABLE_SERVER, rc, ucredp); 1355 break; 1356 case stat_enable_server: 1357 ilbd_audit_server_event(&audit_sg_data, 1358 ILBD_ENABLE_SERVER, rc, ucredp); 1359 break; 1360 } 1361 goto rollback_rules; 1362 } 1363 if (!RULE_HAS_HC(irl)) 1364 continue; 1365 1366 if (cmd == stat_disable_server) { 1367 rc = ilbd_hc_disable_server(irl, 1368 &tmp_srv->isv_srv); 1369 } else { 1370 assert(cmd == stat_enable_server); 1371 rc = ilbd_hc_enable_server(irl, 1372 &tmp_srv->isv_srv); 1373 } 1374 if (rc != ILB_STATUS_OK) { 1375 logdebug("ilbd_Xable_server: cannot toggle srv " 1376 "timer, rc =%d, srv =%s%d\n", rc, 1377 tmp_srv->isv_srvID, 1378 tmp_srv->isv_id); 1379 } 1380 } 1381 1382 /* 2. */ 1383 if ((cmd == stat_disable_server && 1384 IS_SRV_DISABLED(&tmp_srv->isv_srv)) || 1385 (cmd == stat_enable_server && 1386 IS_SRV_ENABLED(&tmp_srv->isv_srv))) { 1387 switch (cmd) { 1388 case stat_disable_server: 1389 ilbd_audit_server_event(&audit_sg_data, 1390 ILBD_DISABLE_SERVER, ILB_STATUS_OK, ucredp); 1391 break; 1392 case stat_enable_server: 1393 ilbd_audit_server_event(&audit_sg_data, 1394 ILBD_ENABLE_SERVER, ILB_STATUS_OK, ucredp); 1395 break; 1396 } 1397 return (ILB_STATUS_OK); 1398 } 1399 1400 nflags = tmp_srv->isv_flags; 1401 if (cmd == stat_enable_server) 1402 ILB_SET_ENABLED(nflags); 1403 else 1404 ILB_SET_DISABLED(nflags); 1405 1406 IP_COPY_IMPL_2_CLI(&tmp_srv->isv_addr, &ipaddr); 1407 ipver = GET_AF(&tmp_srv->isv_addr); 1408 vallen = (ipver == AF_INET) ? INET_ADDRSTRLEN : 1409 INET6_ADDRSTRLEN; 1410 addrptr = (ipver == AF_INET) ? (void *)&ipaddr.ia_v4 : 1411 (void *)&ipaddr.ia_v6; 1412 if (inet_ntop(ipver, addrptr, ipstr, vallen) == NULL) { 1413 logerr("ilbd_Xable_server: failed transfer ip addr to" 1414 " str"); 1415 if (errno == ENOSPC) 1416 rc = ILB_STATUS_ENOMEM; 1417 else 1418 rc = ILB_STATUS_GENERIC; 1419 switch (cmd) { 1420 case stat_disable_server: 1421 ilbd_audit_server_event(&audit_sg_data, 1422 ILBD_DISABLE_SERVER, rc, ucredp); 1423 break; 1424 case stat_enable_server: 1425 ilbd_audit_server_event(&audit_sg_data, 1426 ILBD_ENABLE_SERVER, rc, ucredp); 1427 break; 1428 } 1429 goto rollback_rules; 1430 } 1431 1432 if ((prop_name = malloc(scf_name_len)) == NULL) 1433 return (ILB_STATUS_ENOMEM); 1434 if ((valstr = malloc(scf_val_len)) == NULL) { 1435 free(prop_name); 1436 return (ILB_STATUS_ENOMEM); 1437 } 1438 1439 (void) snprintf(valstr, scf_val_len, "%s;%d;%d-%d;%d", 1440 ipstr, ipver, 1441 ntohs(tmp_srv->isv_minport), 1442 ntohs(tmp_srv->isv_maxport), nflags); 1443 (void) snprintf(prop_name, scf_name_len, "server%d", 1444 tmp_srv->isv_id); 1445 1446 switch (cmd) { 1447 case stat_disable_server: 1448 rc = i_ilbd_save_sg(isg, ILBD_SCF_ENABLE_DISABLE, 1449 prop_name, valstr); 1450 if (rc == ILB_STATUS_OK) 1451 SET_SRV_DISABLED(&tmp_srv->isv_srv); 1452 break; 1453 case stat_enable_server: 1454 rc = i_ilbd_save_sg(isg, ILBD_SCF_ENABLE_DISABLE, 1455 prop_name, valstr); 1456 if (rc == ILB_STATUS_OK) 1457 SET_SRV_ENABLED(&tmp_srv->isv_srv); 1458 break; 1459 } 1460 free(prop_name); 1461 free(valstr); 1462 if (rc == ILB_STATUS_OK) { 1463 switch (cmd) { 1464 case stat_disable_server: 1465 ilbd_audit_server_event(&audit_sg_data, 1466 ILBD_DISABLE_SERVER, ILB_STATUS_OK, ucredp); 1467 break; 1468 case stat_enable_server: 1469 ilbd_audit_server_event(&audit_sg_data, 1470 ILBD_ENABLE_SERVER, ILB_STATUS_OK, ucredp); 1471 break; 1472 } 1473 return (ILB_STATUS_OK); 1474 } 1475 1476 rollback_rules: 1477 if (cmd == stat_disable_server) 1478 u_cmd = stat_enable_server; 1479 else 1480 u_cmd = stat_disable_server; 1481 1482 if (irl == NULL) 1483 irl = list_tail(&isg->isg_rulelist); 1484 else 1485 irl = list_prev(&isg->isg_rulelist, irl); 1486 1487 for (; irl != NULL; irl = list_prev(&isg->isg_rulelist, irl)) { 1488 (void) ilbd_k_Xable_server(&tmp_srv->isv_addr, 1489 irl->irl_name, u_cmd); 1490 if (!RULE_HAS_HC(irl)) 1491 continue; 1492 1493 if (u_cmd == stat_disable_server) 1494 (void) ilbd_hc_disable_server(irl, &tmp_srv->isv_srv); 1495 else 1496 (void) ilbd_hc_enable_server(irl, &tmp_srv->isv_srv); 1497 } 1498 1499 return (rc); 1500 } 1501 1502 ilb_status_t 1503 ilbd_disable_server(ilb_sg_info_t *sg, const struct passwd *ps, 1504 ucred_t *ucredp) 1505 { 1506 return (ilbd_Xable_server(sg, ps, stat_disable_server, ucredp)); 1507 } 1508 1509 ilb_status_t 1510 ilbd_enable_server(ilb_sg_info_t *sg, const struct passwd *ps, 1511 ucred_t *ucredp) 1512 { 1513 return (ilbd_Xable_server(sg, ps, stat_enable_server, ucredp)); 1514 } 1515 1516 /* 1517 * fill in the srvID for the given IP address in the 0th server 1518 */ 1519 ilb_status_t 1520 ilbd_address_to_srvID(ilb_sg_info_t *sg, uint32_t *rbuf, size_t *rbufsz) 1521 { 1522 ilbd_srv_t *tmp_srv; 1523 ilb_sg_srv_t *tsrv; 1524 ilbd_sg_t *tmp_sg; 1525 1526 ilbd_reply_ok(rbuf, rbufsz); 1527 tsrv = (ilb_sg_srv_t *)&((ilb_comm_t *)rbuf)->ic_data; 1528 *rbufsz += sizeof (ilb_sg_srv_t); 1529 1530 tmp_sg = i_find_sg_byname(sg->sg_name); 1531 if (tmp_sg == NULL) 1532 return (ILB_STATUS_SGUNAVAIL); 1533 tsrv->sgs_addr = sg->sg_servers[0].sgs_addr; 1534 1535 tmp_srv = i_find_srv(&tmp_sg->isg_srvlist, tsrv, MODE_ADDR); 1536 if (tmp_srv == NULL) 1537 return (ILB_STATUS_ENOENT); 1538 1539 (void) strlcpy(tsrv->sgs_srvID, tmp_srv->isv_srvID, 1540 sizeof (tsrv->sgs_srvID)); 1541 1542 return (ILB_STATUS_OK); 1543 } 1544 1545 /* 1546 * fill in the address for the given serverID in the 0th server 1547 */ 1548 ilb_status_t 1549 ilbd_srvID_to_address(ilb_sg_info_t *sg, uint32_t *rbuf, size_t *rbufsz) 1550 { 1551 ilbd_srv_t *tmp_srv; 1552 ilb_sg_srv_t *tsrv; 1553 ilbd_sg_t *tmp_sg; 1554 1555 ilbd_reply_ok(rbuf, rbufsz); 1556 tsrv = (ilb_sg_srv_t *)&((ilb_comm_t *)rbuf)->ic_data; 1557 1558 tmp_sg = i_find_sg_byname(sg->sg_name); 1559 if (tmp_sg == NULL) 1560 return (ILB_STATUS_SGUNAVAIL); 1561 (void) strlcpy(tsrv->sgs_srvID, sg->sg_servers[0].sgs_srvID, 1562 sizeof (tsrv->sgs_srvID)); 1563 1564 tmp_srv = i_find_srv(&tmp_sg->isg_srvlist, tsrv, MODE_SRVID); 1565 if (tmp_srv == NULL) 1566 return (ILB_STATUS_ENOENT); 1567 1568 tsrv->sgs_addr = tmp_srv->isv_addr; 1569 *rbufsz += sizeof (ilb_sg_srv_t); 1570 1571 return (ILB_STATUS_OK); 1572 } 1573 1574 /* 1575 * Map ilb_status errors to similar errno values from errno.h or 1576 * adt_event.h to be used for audit record 1577 */ 1578 int 1579 ilberror2auditerror(ilb_status_t rc) 1580 { 1581 int audit_error; 1582 1583 switch (rc) { 1584 case ILB_STATUS_CFGAUTH: 1585 audit_error = ADT_FAIL_VALUE_AUTH; 1586 break; 1587 case ILB_STATUS_ENOMEM: 1588 audit_error = ENOMEM; 1589 break; 1590 case ILB_STATUS_ENOENT: 1591 case ILB_STATUS_ENOHCINFO: 1592 case ILB_STATUS_INVAL_HCTESTTYPE: 1593 case ILB_STATUS_INVAL_CMD: 1594 case ILB_STATUS_DUP_RULE: 1595 case ILB_STATUS_ENORULE: 1596 case ILB_STATUS_SGUNAVAIL: 1597 audit_error = ENOENT; 1598 break; 1599 case ILB_STATUS_EINVAL: 1600 case ILB_STATUS_MISMATCHSG: 1601 case ILB_STATUS_MISMATCHH: 1602 case ILB_STATUS_BADSG: 1603 case ILB_STATUS_INVAL_SRVR: 1604 case ILB_STATUS_INVAL_ENBSRVR: 1605 case ILB_STATUS_BADPORT: 1606 audit_error = EINVAL; 1607 break; 1608 case ILB_STATUS_EEXIST: 1609 case ILB_STATUS_SGEXISTS: 1610 audit_error = EEXIST; 1611 break; 1612 case ILB_STATUS_EWOULDBLOCK: 1613 audit_error = EWOULDBLOCK; 1614 break; 1615 case ILB_STATUS_INPROGRESS: 1616 audit_error = EINPROGRESS; 1617 break; 1618 case ILB_STATUS_INTERNAL: 1619 case ILB_STATUS_CALLBACK: 1620 case ILB_STATUS_PERMIT: 1621 case ILB_STATUS_RULE_NO_HC: 1622 audit_error = ADT_FAIL_VALUE_PROGRAM; 1623 break; 1624 case ILB_STATUS_SOCKET: 1625 audit_error = ENOTSOCK; 1626 break; 1627 case ILB_STATUS_READ: 1628 case ILB_STATUS_WRITE: 1629 audit_error = ENOTCONN; 1630 break; 1631 case ILB_STATUS_SGINUSE: 1632 audit_error = EADDRINUSE; 1633 break; 1634 case ILB_STATUS_SEND: 1635 audit_error = ECOMM; 1636 break; 1637 case ILB_STATUS_SGFULL: 1638 audit_error = EOVERFLOW; 1639 break; 1640 case ILB_STATUS_NAMETOOLONG: 1641 audit_error = ENAMETOOLONG; 1642 break; 1643 case ILB_STATUS_SRVUNAVAIL: 1644 audit_error = EHOSTUNREACH; 1645 break; 1646 default: 1647 audit_error = ADT_FAIL_VALUE_UNKNOWN; 1648 break; 1649 } 1650 return (audit_error); 1651 } 1652