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