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