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