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 <unistd.h> 30 #include <sys/types.h> 31 #include <sys/socket.h> 32 #include <netinet/in.h> 33 #include <arpa/inet.h> 34 #include <sys/list.h> 35 #include <net/if.h> 36 #include <assert.h> 37 #include <errno.h> 38 #include <libintl.h> 39 #include <libilb.h> 40 #include <inet/ilb.h> 41 #include "libilb_impl.h" 42 #include "ilbd.h" 43 44 /* until we all use AF_* macros ... */ 45 #define AF_2_IPPROTO(_af) (_af == AF_INET)?IPPROTO_IP:IPPROTO_IPV6 46 #define IPPROTO_2_AF(_i) (_i == IPPROTO_IP)?AF_INET:AF_INET6 47 48 #define PROTOCOL_LEN 16 /* protocol type */ 49 #define ADDR_LEN (2 * INET6_ADDRSTRLEN + 1) /* prxy src range */ 50 #define PORT_LEN 6 /* hcport:1-65535 or "ANY" */ 51 52 static ilb_status_t ilbd_disable_one_rule(ilbd_rule_t *, boolean_t); 53 static uint32_t i_flags_d2k(int); 54 55 #define ILB_SGSRV_2_KSRV(s, k) \ 56 (k)->addr = (s)->sgs_addr; \ 57 (k)->min_port = (s)->sgs_minport; \ 58 (k)->max_port = (s)->sgs_maxport; \ 59 (k)->flags = i_flags_d2k((s)->sgs_flags); \ 60 (k)->err = 0; \ 61 (void) strlcpy((k)->name, (s)->sgs_srvID, sizeof ((k)->name)) 62 63 list_t ilbd_rule_hlist; 64 65 static ilb_algo_t 66 algo_impl2lib(ilb_algo_impl_t a) 67 { 68 switch (a) { 69 case ILB_ALG_IMPL_ROUNDROBIN: 70 return (ILB_ALG_ROUNDROBIN); 71 case ILB_ALG_IMPL_HASH_IP: 72 return (ILB_ALG_HASH_IP); 73 case ILB_ALG_IMPL_HASH_IP_SPORT: 74 return (ILB_ALG_HASH_IP_SPORT); 75 case ILB_ALG_IMPL_HASH_IP_VIP: 76 return (ILB_ALG_HASH_IP_VIP); 77 } 78 return (0); 79 } 80 81 static ilb_topo_t 82 topo_impl2lib(ilb_topo_impl_t t) 83 { 84 switch (t) { 85 case ILB_TOPO_IMPL_DSR: 86 return (ILB_TOPO_DSR); 87 case ILB_TOPO_IMPL_NAT: 88 return (ILB_TOPO_NAT); 89 case ILB_TOPO_IMPL_HALF_NAT: 90 return (ILB_TOPO_HALF_NAT); 91 } 92 return (0); 93 } 94 95 ilb_algo_impl_t 96 algo_lib2impl(ilb_algo_t a) 97 { 98 switch (a) { 99 case ILB_ALG_ROUNDROBIN: 100 return (ILB_ALG_IMPL_ROUNDROBIN); 101 case ILB_ALG_HASH_IP: 102 return (ILB_ALG_IMPL_HASH_IP); 103 case ILB_ALG_HASH_IP_SPORT: 104 return (ILB_ALG_IMPL_HASH_IP_SPORT); 105 case ILB_ALG_HASH_IP_VIP: 106 return (ILB_ALG_IMPL_HASH_IP_VIP); 107 } 108 return (0); 109 } 110 111 ilb_topo_impl_t 112 topo_lib2impl(ilb_topo_t t) 113 { 114 switch (t) { 115 case ILB_TOPO_DSR: 116 return (ILB_TOPO_IMPL_DSR); 117 case ILB_TOPO_NAT: 118 return (ILB_TOPO_IMPL_NAT); 119 case ILB_TOPO_HALF_NAT: 120 return (ILB_TOPO_IMPL_HALF_NAT); 121 } 122 return (0); 123 } 124 125 /* 126 * Walk the list of rules and check if its safe to add the 127 * the server to the rule (this is a list of rules hanging 128 * off of a server group) 129 */ 130 ilb_status_t 131 i_check_srv2rules(list_t *rlist, ilb_sg_srv_t *srv) 132 { 133 ilb_status_t rc = ILB_STATUS_OK; 134 ilbd_rule_t *rl; 135 int server_portrange, rule_portrange; 136 int srv_minport, srv_maxport; 137 int r_minport, r_maxport; 138 139 if (srv == NULL) 140 return (ILB_STATUS_OK); 141 142 srv_minport = ntohs(srv->sgs_minport); 143 srv_maxport = ntohs(srv->sgs_maxport); 144 145 for (rl = list_head(rlist); rl != NULL; rl = list_next(rlist, rl)) { 146 r_minport = ntohs(rl->irl_minport); 147 r_maxport = ntohs(rl->irl_maxport); 148 149 if ((srv_minport != 0) && (srv_minport == srv_maxport)) { 150 /* server has single port */ 151 if (rl->irl_topo == ILB_TOPO_DSR) { 152 /* 153 * either we have a DSR rule with a port 154 * range, or both server and rule 155 * have single ports but their values 156 * don't match - this is incompatible 157 */ 158 if (r_maxport > r_minport) { 159 rc = ILB_STATUS_INVAL_SRVR; 160 break; 161 } else if (srv_minport != r_minport) { 162 rc = ILB_STATUS_BADPORT; 163 break; 164 } 165 } 166 if (rl->irl_hcpflag == ILB_HCI_PROBE_FIX && 167 rl->irl_hcport != srv_minport) { 168 rc = ILB_STATUS_BADPORT; 169 break; 170 } 171 } else if (srv_maxport > srv_minport) { 172 /* server has a port range */ 173 if ((rl->irl_topo == ILB_TOPO_DSR) && 174 (r_maxport > r_minport)) { 175 if ((r_minport != srv_minport) || 176 (r_maxport != srv_maxport)) { 177 /* 178 * we have a DSR rule with a port range 179 * and its min and max port values 180 * does not meet that of server's 181 * - this is incompatible 182 */ 183 rc = ILB_STATUS_BADPORT; 184 break; 185 } 186 } else if ((rl->irl_topo == ILB_TOPO_DSR) && 187 (r_maxport == r_minport)) { 188 /* 189 * we have a DSR rule with a single 190 * port and a server with a port range 191 * - this is incompatible 192 */ 193 rc = ILB_STATUS_INVAL_SRVR; 194 break; 195 } else if (((rl->irl_topo == ILB_TOPO_NAT) || 196 (rl->irl_topo == ILB_TOPO_HALF_NAT)) && 197 (r_maxport > r_minport)) { 198 server_portrange = srv_maxport - srv_minport; 199 rule_portrange = r_maxport - r_minport; 200 if (rule_portrange != server_portrange) { 201 /* 202 * we have a NAT/Half-NAT rule with 203 * a port range and server with a port 204 * range and there is a mismatch in the 205 * sizes of the port ranges - this is 206 * incompatible 207 */ 208 rc = ILB_STATUS_INVAL_SRVR; 209 break; 210 } 211 } 212 if (rl->irl_hcpflag == ILB_HCI_PROBE_FIX && 213 (rl->irl_hcport > srv_maxport || 214 rl->irl_hcport < srv_minport)) { 215 rc = ILB_STATUS_BADPORT; 216 break; 217 } 218 } 219 } 220 221 return (rc); 222 } 223 224 void 225 i_setup_rule_hlist(void) 226 { 227 list_create(&ilbd_rule_hlist, sizeof (ilbd_rule_t), 228 offsetof(ilbd_rule_t, irl_link)); 229 } 230 231 ilb_status_t 232 i_ilbd_save_rule(ilbd_rule_t *irl, ilbd_scf_cmd_t scf_cmd) 233 { 234 boolean_t enable = irl->irl_flags & ILB_FLAGS_RULE_ENABLED; 235 236 switch (scf_cmd) { 237 case ILBD_SCF_CREATE: 238 return (ilbd_create_pg(ILBD_SCF_RULE, (void *)irl)); 239 case ILBD_SCF_DESTROY: 240 return (ilbd_destroy_pg(ILBD_SCF_RULE, irl->irl_name)); 241 case ILBD_SCF_ENABLE_DISABLE: 242 return (ilbd_change_prop(ILBD_SCF_RULE, irl->irl_name, 243 "status", &enable)); 244 default: 245 logdebug("i_ilbd_save_rule: invalid scf cmd %d", scf_cmd); 246 return (ILB_STATUS_INVAL_CMD); 247 } 248 } 249 250 /* 251 * allocate a new daemon-specific rule from the "template" passed 252 * in in *r 253 */ 254 static ilbd_rule_t * 255 i_alloc_ilbd_rule(ilb_rule_info_t *r) 256 { 257 ilbd_rule_t *rl; 258 259 rl = calloc(sizeof (*rl), 1); 260 if (rl != NULL && r != NULL) 261 bcopy(r, &rl->irl_info, sizeof (*r)); 262 263 return (rl); 264 } 265 266 static ilbd_rule_t * 267 i_find_rule_byname(const char *name) 268 { 269 ilbd_rule_t *rl; 270 271 /* find position of rule in list */ 272 rl = list_head(&ilbd_rule_hlist); 273 while (rl != NULL && 274 strncmp(rl->irl_name, name, sizeof (rl->irl_name)) != 0) { 275 rl = list_next(&ilbd_rule_hlist, rl); 276 } 277 278 return (rl); 279 } 280 281 /* 282 * get exactly one rule (named in rl->irl_name) data from kernel 283 */ 284 static ilb_status_t 285 ilb_get_krule(ilb_rule_info_t *rl) 286 { 287 ilb_status_t rc; 288 ilb_rule_cmd_t kcmd; 289 290 kcmd.cmd = ILB_LIST_RULE; 291 (void) strlcpy(kcmd.name, rl->rl_name, sizeof (kcmd.name)); 292 kcmd.flags = 0; 293 294 rc = do_ioctl(&kcmd, 0); 295 if (rc != ILB_STATUS_OK) 296 return (rc); 297 298 rl->rl_flags = kcmd.flags; 299 rl->rl_ipversion = IPPROTO_2_AF(kcmd.ip_ver); 300 rl->rl_vip = kcmd.vip; 301 rl->rl_proto = kcmd.proto; 302 rl->rl_minport = kcmd.min_port; 303 rl->rl_maxport = kcmd.max_port; 304 rl->rl_algo = algo_impl2lib(kcmd.algo); 305 rl->rl_topo = topo_impl2lib(kcmd.topo); 306 rl->rl_stickymask = kcmd.sticky_mask; 307 rl->rl_nat_src_start = kcmd.nat_src_start; 308 rl->rl_nat_src_end = kcmd.nat_src_end; 309 (void) strlcpy(rl->rl_name, kcmd.name, sizeof (rl->rl_name)); 310 rl->rl_conndrain = kcmd.conn_drain_timeout; 311 rl->rl_nat_timeout = kcmd.nat_expiry; 312 rl->rl_sticky_timeout = kcmd.sticky_expiry; 313 314 return (ILB_STATUS_OK); 315 } 316 317 ilb_status_t 318 ilbd_retrieve_rule(ilbd_name_t rl_name, uint32_t *rbuf, size_t *rbufsz) 319 { 320 ilbd_rule_t *irl = NULL; 321 ilb_status_t rc; 322 ilb_rule_info_t *rinfo; 323 324 irl = i_find_rule_byname(rl_name); 325 if (irl == NULL) 326 return (ILB_STATUS_ENOENT); 327 328 ilbd_reply_ok(rbuf, rbufsz); 329 rinfo = (ilb_rule_info_t *)&((ilb_comm_t *)rbuf)->ic_data; 330 bcopy(&irl->irl_info, rinfo, sizeof (*rinfo)); 331 332 /* 333 * Check if the various timeout values are 0. If one is, get the 334 * default values from kernel. 335 */ 336 if (rinfo->rl_conndrain == 0 || rinfo->rl_nat_timeout == 0 || 337 rinfo->rl_sticky_timeout == 0) { 338 ilb_rule_info_t tmp_info; 339 340 (void) strcpy(tmp_info.rl_name, rinfo->rl_name); 341 rc = ilb_get_krule(&tmp_info); 342 if (rc != ILB_STATUS_OK) 343 return (rc); 344 if (rinfo->rl_conndrain == 0) 345 rinfo->rl_conndrain = tmp_info.rl_conndrain; 346 if ((rinfo->rl_topo == ILB_TOPO_NAT || 347 rinfo->rl_topo == ILB_TOPO_HALF_NAT) && 348 rinfo->rl_nat_timeout == 0) { 349 rinfo->rl_nat_timeout = tmp_info.rl_nat_timeout; 350 } 351 if ((rinfo->rl_flags & ILB_FLAGS_RULE_STICKY) && 352 rinfo->rl_sticky_timeout == 0) { 353 rinfo->rl_sticky_timeout = tmp_info.rl_sticky_timeout; 354 } 355 } 356 *rbufsz += sizeof (ilb_rule_info_t); 357 358 return (ILB_STATUS_OK); 359 } 360 361 static ilb_status_t 362 ilbd_destroy_one_rule(ilbd_rule_t *irl) 363 { 364 ilb_status_t rc; 365 ilb_name_cmd_t kcmd; 366 367 /* 368 * as far as talking to the kernel is concerned, "all rules" 369 * is handled in one go somewhere else, so we only 370 * tell the kernel about single rules here. 371 */ 372 if ((irl->irl_flags & ILB_FLAGS_RULE_ALLRULES) == 0) { 373 kcmd.cmd = ILB_DESTROY_RULE; 374 (void) strlcpy(kcmd.name, irl->irl_name, sizeof (kcmd.name)); 375 kcmd.flags = 0; 376 377 rc = do_ioctl(&kcmd, 0); 378 if (rc != ILB_STATUS_OK) 379 return (rc); 380 381 } 382 list_remove(&irl->irl_sg->isg_rulelist, irl); 383 list_remove(&ilbd_rule_hlist, irl); 384 385 /* 386 * When dissociating a rule, only two errors can happen. The hc 387 * name is incorrect or the rule is not associated with the hc 388 * object. Both should not happen.... The check is for debugging 389 * purpose. 390 */ 391 if (RULE_HAS_HC(irl) && (rc = ilbd_hc_dissociate_rule(irl)) != 392 ILB_STATUS_OK) { 393 logerr("ilbd_destroy_one_rule: cannot " 394 "dissociate %s from hc object %s: %d", 395 irl->irl_name, irl->irl_hcname, rc); 396 } 397 398 rc = i_ilbd_save_rule(irl, ILBD_SCF_DESTROY); 399 if (rc != ILB_STATUS_OK) 400 logdebug("ilbd_destroy_rule: save rule failed"); 401 402 free(irl); 403 return (rc); 404 } 405 406 /* 407 * the following two functions are the other's opposite, and can 408 * call into each other for roll back purposes in case of error. 409 * To avoid endless recursion, the 'is_rollback' parameter must be 410 * set to B_TRUE in the roll back case. 411 */ 412 static ilb_status_t 413 ilbd_enable_one_rule(ilbd_rule_t *irl, boolean_t is_rollback) 414 { 415 ilb_status_t rc = ILB_STATUS_OK; 416 ilb_name_cmd_t kcmd; 417 418 /* no use sending a no-op to the kernel */ 419 if ((irl->irl_flags & ILB_FLAGS_RULE_ENABLED) != 0) 420 return (ILB_STATUS_OK); 421 422 irl->irl_flags |= ILB_FLAGS_RULE_ENABLED; 423 424 /* "all rules" is handled in one go somewhere else, not here */ 425 if ((irl->irl_flags & ILB_FLAGS_RULE_ALLRULES) == 0) { 426 kcmd.cmd = ILB_ENABLE_RULE; 427 (void) strlcpy(kcmd.name, irl->irl_name, sizeof (kcmd.name)); 428 kcmd.flags = 0; 429 430 rc = do_ioctl(&kcmd, 0); 431 if (rc != ILB_STATUS_OK) 432 return (rc); 433 } 434 if (RULE_HAS_HC(irl) && (rc = ilbd_hc_enable_rule(irl)) != 435 ILB_STATUS_OK) { 436 /* Undo the kernel work */ 437 kcmd.cmd = ILB_DISABLE_RULE; 438 /* Cannot do much if ioctl fails... */ 439 (void) do_ioctl(&kcmd, 0); 440 return (rc); 441 } 442 443 if (!is_rollback) { 444 if (rc == ILB_STATUS_OK) 445 rc = i_ilbd_save_rule(irl, ILBD_SCF_ENABLE_DISABLE); 446 if (rc != ILB_STATUS_OK) 447 /* ignore rollback return code */ 448 (void) ilbd_disable_one_rule(irl, B_TRUE); 449 } 450 451 return (rc); 452 } 453 454 static ilb_status_t 455 ilbd_disable_one_rule(ilbd_rule_t *irl, boolean_t is_rollback) 456 { 457 ilb_status_t rc = ILB_STATUS_OK; 458 ilb_name_cmd_t kcmd; 459 460 /* no use sending a no-op to the kernel */ 461 if ((irl->irl_flags & ILB_FLAGS_RULE_ENABLED) == 0) 462 return (ILB_STATUS_OK); 463 464 irl->irl_flags &= ~ILB_FLAGS_RULE_ENABLED; 465 466 /* "all rules" is handled in one go somewhere else, not here */ 467 if ((irl->irl_flags & ILB_FLAGS_RULE_ALLRULES) == 0) { 468 kcmd.cmd = ILB_DISABLE_RULE; 469 (void) strlcpy(kcmd.name, irl->irl_name, sizeof (kcmd.name)); 470 kcmd.flags = 0; 471 472 rc = do_ioctl(&kcmd, 0); 473 if (rc != ILB_STATUS_OK) 474 return (rc); 475 } 476 477 if (RULE_HAS_HC(irl) && (rc = ilbd_hc_disable_rule(irl)) != 478 ILB_STATUS_OK) { 479 /* Undo the kernel work */ 480 kcmd.cmd = ILB_ENABLE_RULE; 481 /* Cannot do much if ioctl fails... */ 482 (void) do_ioctl(&kcmd, 0); 483 return (rc); 484 } 485 486 if (!is_rollback) { 487 if (rc == ILB_STATUS_OK) 488 rc = i_ilbd_save_rule(irl, ILBD_SCF_ENABLE_DISABLE); 489 if (rc != ILB_STATUS_OK) 490 /* ignore rollback return code */ 491 (void) ilbd_enable_one_rule(irl, B_TRUE); 492 } 493 494 return (rc); 495 } 496 497 /* 498 * Generates an audit record for a supplied rule name 499 * Used for enable_rule, disable_rule, delete_rule, 500 * and create_rule subcommands 501 */ 502 static void 503 ilbd_audit_rule_event(const char *audit_rule_name, 504 ilb_rule_info_t *rlinfo, ilbd_cmd_t cmd, ilb_status_t rc, 505 ucred_t *ucredp) 506 { 507 adt_session_data_t *ah; 508 adt_event_data_t *event; 509 au_event_t flag; 510 int scf_val_len = ILBD_MAX_VALUE_LEN; 511 char *aobuf = NULL; /* algo:topo */ 512 char *valstr1 = NULL; 513 char *valstr2 = NULL; 514 char pbuf[PROTOCOL_LEN]; /* protocol */ 515 char hcpbuf[PORT_LEN]; /* hcport */ 516 int audit_error; 517 518 if ((ucredp == NULL) && (cmd == ILBD_CREATE_RULE)) { 519 /* 520 * we came here from the path where ilbd incorporates 521 * the configuration that is listed in SCF : 522 * i_ilbd_read_config->ilbd_walk_rule_pgs-> 523 * ->ilbd_scf_instance_walk_pg->ilbd_create_rule 524 * We skip auditing in that case 525 */ 526 return; 527 } 528 if (adt_start_session(&ah, NULL, 0) != 0) { 529 logerr("ilbd_audit_rule_event: adt_start_session failed"); 530 exit(EXIT_FAILURE); 531 } 532 if (adt_set_from_ucred(ah, ucredp, ADT_NEW) != 0) { 533 (void) adt_end_session(ah); 534 logerr("ilbd_audit_rule_event: adt_set_from_ucred failed"); 535 exit(EXIT_FAILURE); 536 } 537 if (cmd == ILBD_ENABLE_RULE) 538 flag = ADT_ilb_enable_rule; 539 else if (cmd == ILBD_DISABLE_RULE) 540 flag = ADT_ilb_disable_rule; 541 else if (cmd == ILBD_DESTROY_RULE) 542 flag = ADT_ilb_delete_rule; 543 else if (cmd == ILBD_CREATE_RULE) 544 flag = ADT_ilb_create_rule; 545 546 if ((event = adt_alloc_event(ah, flag)) == NULL) { 547 logerr("ilbd_audit_rule_event: adt_alloc_event failed"); 548 exit(EXIT_FAILURE); 549 } 550 551 (void) memset((char *)event, 0, sizeof (adt_event_data_t)); 552 553 switch (cmd) { 554 case ILBD_DESTROY_RULE: 555 event->adt_ilb_delete_rule.auth_used = NET_ILB_CONFIG_AUTH; 556 event->adt_ilb_delete_rule.rule_name = (char *)audit_rule_name; 557 break; 558 case ILBD_ENABLE_RULE: 559 event->adt_ilb_enable_rule.auth_used = NET_ILB_ENABLE_AUTH; 560 event->adt_ilb_enable_rule.rule_name = (char *)audit_rule_name; 561 break; 562 case ILBD_DISABLE_RULE: 563 event->adt_ilb_disable_rule.auth_used = NET_ILB_ENABLE_AUTH; 564 event->adt_ilb_disable_rule.rule_name = (char *)audit_rule_name; 565 break; 566 case ILBD_CREATE_RULE: 567 if (((aobuf = malloc(scf_val_len)) == NULL) || 568 ((valstr1 = malloc(scf_val_len)) == NULL) || 569 ((valstr2 = malloc(scf_val_len)) == NULL)) { 570 logerr("ilbd_audit_rule_event: could not" 571 " allocate buffer"); 572 exit(EXIT_FAILURE); 573 } 574 575 event->adt_ilb_create_rule.auth_used = NET_ILB_CONFIG_AUTH; 576 577 /* Fill in virtual IP address type */ 578 if (IN6_IS_ADDR_V4MAPPED(&rlinfo->rl_vip)) { 579 event->adt_ilb_create_rule.virtual_ipaddress_type = 580 ADT_IPv4; 581 cvt_addr(event->adt_ilb_create_rule.virtual_ipaddress, 582 ADT_IPv4, rlinfo->rl_vip); 583 } else { 584 event->adt_ilb_create_rule.virtual_ipaddress_type = 585 ADT_IPv6; 586 cvt_addr(event->adt_ilb_create_rule.virtual_ipaddress, 587 ADT_IPv6, rlinfo->rl_vip); 588 } 589 /* Fill in port - could be a single value or a range */ 590 event->adt_ilb_create_rule.min_port = ntohs(rlinfo->rl_minport); 591 if (ntohs(rlinfo->rl_maxport) > ntohs(rlinfo->rl_minport)) { 592 /* port range */ 593 event->adt_ilb_create_rule.max_port = 594 ntohs(rlinfo->rl_maxport); 595 } else { 596 /* in audit record, max=min when single port */ 597 event->adt_ilb_create_rule.max_port = 598 ntohs(rlinfo->rl_minport); 599 } 600 601 /* 602 * Fill in protocol - if user does not specify it, 603 * its TCP by default 604 */ 605 if (rlinfo->rl_proto == IPPROTO_UDP) 606 (void) snprintf(pbuf, PROTOCOL_LEN, "UDP"); 607 else 608 (void) snprintf(pbuf, PROTOCOL_LEN, "TCP"); 609 event->adt_ilb_create_rule.protocol = pbuf; 610 611 /* Fill in algorithm and operation type */ 612 ilbd_algo_to_str(rlinfo->rl_algo, valstr1); 613 ilbd_topo_to_str(rlinfo->rl_topo, valstr2); 614 (void) snprintf(aobuf, scf_val_len, "%s:%s", 615 valstr1, valstr2); 616 event->adt_ilb_create_rule.algo_optype = aobuf; 617 618 /* Fill in proxy-src for the NAT case */ 619 if (rlinfo->rl_topo == ILB_TOPO_NAT) { 620 /* copy starting proxy-src address */ 621 if (IN6_IS_ADDR_V4MAPPED(&rlinfo->rl_nat_src_start)) { 622 /* V4 case */ 623 event->adt_ilb_create_rule.proxy_src_min_type = 624 ADT_IPv4; 625 cvt_addr( 626 event->adt_ilb_create_rule.proxy_src_min, 627 ADT_IPv4, rlinfo->rl_nat_src_start); 628 } else { 629 /* V6 case */ 630 event->adt_ilb_create_rule.proxy_src_min_type = 631 ADT_IPv6; 632 cvt_addr( 633 event->adt_ilb_create_rule.proxy_src_min, 634 ADT_IPv6, rlinfo->rl_nat_src_start); 635 } 636 637 /* copy ending proxy-src address */ 638 if (&rlinfo->rl_nat_src_end == 0) { 639 /* proxy-src is a single address */ 640 event->adt_ilb_create_rule.proxy_src_max_type = 641 event-> 642 adt_ilb_create_rule.proxy_src_min_type; 643 (void) memcpy( 644 event->adt_ilb_create_rule.proxy_src_max, 645 event->adt_ilb_create_rule.proxy_src_min, 646 (4 * sizeof (uint32_t))); 647 } else if ( 648 IN6_IS_ADDR_V4MAPPED(&rlinfo->rl_nat_src_end)) { 649 /* 650 * proxy-src is a address range - copy ending 651 * proxy-src address 652 * V4 case 653 */ 654 event->adt_ilb_create_rule.proxy_src_max_type = 655 ADT_IPv4; 656 cvt_addr( 657 event->adt_ilb_create_rule.proxy_src_max, 658 ADT_IPv4, rlinfo->rl_nat_src_end); 659 } else { 660 /* V6 case */ 661 event->adt_ilb_create_rule.proxy_src_max_type = 662 ADT_IPv6; 663 cvt_addr( 664 event->adt_ilb_create_rule.proxy_src_max, 665 ADT_IPv6, rlinfo->rl_nat_src_end); 666 } 667 } 668 669 /* 670 * Fill in pmask if user has specified one - 0 means 671 * no persistence 672 */ 673 valstr1[0] = '\0'; 674 ilbd_ip_to_str(rlinfo->rl_ipversion, &rlinfo->rl_stickymask, 675 valstr1); 676 event->adt_ilb_create_rule.persist_mask = valstr1; 677 678 /* If there is a hcname */ 679 if (rlinfo->rl_hcname[0] != '\0') 680 event->adt_ilb_create_rule.hcname = rlinfo->rl_hcname; 681 682 /* Fill in hcport */ 683 if (rlinfo->rl_hcpflag == ILB_HCI_PROBE_FIX) { 684 /* hcport is specified by user */ 685 (void) snprintf(hcpbuf, PORT_LEN, "%d", 686 rlinfo->rl_hcport); 687 event->adt_ilb_create_rule.hcport = hcpbuf; 688 } else if (rlinfo->rl_hcpflag == ILB_HCI_PROBE_ANY) { 689 /* user has specified "ANY" */ 690 (void) snprintf(hcpbuf, PORT_LEN, "ANY"); 691 event->adt_ilb_create_rule.hcport = hcpbuf; 692 } 693 /* 694 * Fill out the conndrain, nat_timeout and persist_timeout 695 * If the user does not specify them, the default value 696 * is set in the kernel. Userland does not know what 697 * the values are. So if the user 698 * does not specify these values they will show up as 699 * 0 in the audit record. 700 */ 701 event->adt_ilb_create_rule.conndrain_timeout = 702 rlinfo->rl_conndrain; 703 event->adt_ilb_create_rule.nat_timeout = 704 rlinfo->rl_nat_timeout; 705 event->adt_ilb_create_rule.persist_timeout = 706 rlinfo->rl_sticky_timeout; 707 708 /* Fill out servergroup and rule name */ 709 event->adt_ilb_create_rule.server_group = rlinfo->rl_sgname; 710 event->adt_ilb_create_rule.rule_name = rlinfo->rl_name; 711 break; 712 } 713 if (rc == ILB_STATUS_OK) { 714 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { 715 logerr("ilbd_audit_rule_event:adt_put_event failed"); 716 exit(EXIT_FAILURE); 717 } 718 } else { 719 audit_error = ilberror2auditerror(rc); 720 if (adt_put_event(event, ADT_FAILURE, audit_error) != 0) { 721 logerr("ilbd_audit_rule_event: adt_put_event failed"); 722 exit(EXIT_FAILURE); 723 } 724 } 725 adt_free_event(event); 726 free(aobuf); 727 free(valstr1); 728 free(valstr2); 729 (void) adt_end_session(ah); 730 } 731 /* 732 * converts IP address from in6_addr format to uint32_t[4] 733 * This conversion is needed for recording IP address in 734 * audit records. 735 */ 736 void 737 cvt_addr(uint32_t *audit, int32_t type, struct in6_addr address) 738 { 739 740 if (type == ADT_IPv4) { 741 /* address is IPv4 */ 742 audit[0] = address._S6_un._S6_u32[3]; 743 } else { 744 /* address is IPv6 */ 745 (void) memcpy(audit, address._S6_un._S6_u32, 746 (4 * sizeof (uint32_t))); 747 } 748 } 749 750 static ilb_status_t 751 i_ilbd_action_switch(ilbd_rule_t *irl, ilbd_cmd_t cmd, 752 boolean_t is_rollback, ucred_t *ucredp) 753 { 754 ilb_status_t rc; 755 756 switch (cmd) { 757 case ILBD_DESTROY_RULE: 758 rc = ilbd_destroy_one_rule(irl); 759 if (!is_rollback) { 760 ilbd_audit_rule_event(irl->irl_name, NULL, 761 cmd, rc, ucredp); 762 } 763 return (rc); 764 case ILBD_ENABLE_RULE: 765 rc = ilbd_enable_one_rule(irl, is_rollback); 766 if (!is_rollback) { 767 ilbd_audit_rule_event(irl->irl_name, NULL, cmd, 768 rc, ucredp); 769 } 770 return (rc); 771 case ILBD_DISABLE_RULE: 772 rc = ilbd_disable_one_rule(irl, is_rollback); 773 if (!is_rollback) { 774 ilbd_audit_rule_event(irl->irl_name, NULL, cmd, 775 rc, ucredp); 776 } 777 return (rc); 778 } 779 return (ILB_STATUS_INVAL_CMD); 780 } 781 782 static ilb_cmd_t 783 i_ilbd2ilb_cmd(ilbd_cmd_t c) 784 { 785 ilb_cmd_t r; 786 787 switch (c) { 788 case ILBD_CREATE_RULE: 789 r = ILB_CREATE_RULE; 790 break; 791 case ILBD_DESTROY_RULE: 792 r = ILB_DESTROY_RULE; 793 break; 794 case ILBD_ENABLE_RULE: 795 r = ILB_ENABLE_RULE; 796 break; 797 case ILBD_DISABLE_RULE: 798 r = ILB_DISABLE_RULE; 799 break; 800 } 801 return (r); 802 } 803 804 static ilbd_cmd_t 805 get_undo_cmd(ilbd_cmd_t cmd) 806 { 807 ilbd_cmd_t u_cmd; 808 809 switch (cmd) { 810 case ILBD_DESTROY_RULE: 811 u_cmd = ILBD_BAD_CMD; 812 break; 813 case ILBD_ENABLE_RULE: 814 u_cmd = ILBD_DISABLE_RULE; 815 break; 816 case ILBD_DISABLE_RULE: 817 u_cmd = ILBD_ENABLE_RULE; 818 break; 819 } 820 821 return (u_cmd); 822 } 823 824 static ilb_status_t 825 i_ilbd_rule_action(const char *rule_name, const struct passwd *ps, 826 ilbd_cmd_t cmd, ucred_t *ucredp) 827 { 828 ilbd_rule_t *irl, *irl_next; 829 boolean_t is_all_rules = B_FALSE; 830 ilb_status_t rc = ILB_STATUS_OK; 831 ilb_name_cmd_t kcmd; 832 ilbd_cmd_t u_cmd; 833 char rulename[ILB_NAMESZ]; 834 835 if (ps != NULL) { 836 if ((cmd == ILBD_ENABLE_RULE) || (cmd == ILBD_DISABLE_RULE)) 837 rc = ilbd_check_client_enable_auth(ps); 838 else 839 rc = ilbd_check_client_config_auth(ps); 840 /* generate the audit record before bailing out */ 841 if (rc != ILB_STATUS_OK) { 842 if (*rule_name != '\0') { 843 ilbd_audit_rule_event(rule_name, NULL, 844 cmd, rc, ucredp); 845 } else { 846 (void) snprintf(rulename, sizeof (rulename), 847 "all"); 848 ilbd_audit_rule_event(rulename, NULL, cmd, rc, 849 ucredp); 850 } 851 goto out; 852 } 853 } 854 is_all_rules = rule_name[0] == 0; 855 856 /* just one rule */ 857 if (!is_all_rules) { 858 irl = i_find_rule_byname(rule_name); 859 if (irl == NULL) { 860 rc = ILB_STATUS_ENORULE; 861 ilbd_audit_rule_event(rule_name, NULL, cmd, rc, ucredp); 862 goto out; 863 } 864 /* auditing will be done by i_ilbd_action_switch() */ 865 rc = i_ilbd_action_switch(irl, cmd, B_FALSE, ucredp); 866 goto out; 867 } 868 869 /* all rules: first tell the kernel, then walk the daemon's list */ 870 kcmd.cmd = i_ilbd2ilb_cmd(cmd); 871 kcmd.flags = ILB_RULE_ALLRULES; 872 873 rc = do_ioctl(&kcmd, 0); 874 if (rc != ILB_STATUS_OK) { 875 (void) snprintf(rulename, sizeof (rulename), "all"); 876 ilbd_audit_rule_event(rulename, NULL, cmd, rc, ucredp); 877 goto out; 878 } 879 880 irl = list_head(&ilbd_rule_hlist); 881 while (irl != NULL) { 882 irl_next = list_next(&ilbd_rule_hlist, irl); 883 irl->irl_flags |= ILB_FLAGS_RULE_ALLRULES; 884 /* auditing will be done by i_ilbd_action_switch() */ 885 rc = i_ilbd_action_switch(irl, cmd, B_FALSE, ucredp); 886 irl->irl_flags &= ~ILB_FLAGS_RULE_ALLRULES; 887 if (rc != ILB_STATUS_OK) 888 goto rollback_list; 889 irl = irl_next; 890 } 891 return (rc); 892 893 rollback_list: 894 u_cmd = get_undo_cmd(cmd); 895 if (u_cmd == ILBD_BAD_CMD) 896 return (rc); 897 898 if (is_all_rules) { 899 kcmd.cmd = i_ilbd2ilb_cmd(u_cmd); 900 (void) do_ioctl(&kcmd, 0); 901 } 902 /* current list element failed, so we start with previous one */ 903 irl = list_prev(&ilbd_rule_hlist, irl); 904 while (irl != NULL) { 905 if (is_all_rules) 906 irl->irl_flags |= ILB_FLAGS_RULE_ALLRULES; 907 908 /* 909 * When the processing of a command consists of 910 * multiple sequential steps, and one of them fails, 911 * ilbd performs rollback to undo the steps taken before the 912 * failing step. Since ilbd is initiating these steps 913 * there is not need to audit them. 914 */ 915 rc = i_ilbd_action_switch(irl, u_cmd, B_TRUE, NULL); 916 irl->irl_flags &= ~ILB_FLAGS_RULE_ALLRULES; 917 918 irl = list_prev(&ilbd_rule_hlist, irl); 919 } 920 out: 921 return (rc); 922 } 923 924 ilb_status_t 925 ilbd_destroy_rule(ilbd_name_t rule_name, const struct passwd *ps, 926 ucred_t *ucredp) 927 { 928 return (i_ilbd_rule_action(rule_name, ps, ILBD_DESTROY_RULE, ucredp)); 929 } 930 931 ilb_status_t 932 ilbd_enable_rule(ilbd_name_t rule_name, const struct passwd *ps, 933 ucred_t *ucredp) 934 { 935 return (i_ilbd_rule_action(rule_name, ps, ILBD_ENABLE_RULE, ucredp)); 936 937 } 938 939 ilb_status_t 940 ilbd_disable_rule(ilbd_name_t rule_name, const struct passwd *ps, 941 ucred_t *ucredp) 942 { 943 return (i_ilbd_rule_action(rule_name, ps, ILBD_DISABLE_RULE, ucredp)); 944 } 945 946 /* 947 * allocate storage for a kernel rule command and fill from 948 * "template" irl, if non-NULL 949 */ 950 static ilb_rule_cmd_t * 951 i_alloc_kernel_rule_cmd(ilbd_rule_t *irl) 952 { 953 ilb_rule_cmd_t *kcmd; 954 955 kcmd = (ilb_rule_cmd_t *)malloc(sizeof (*kcmd)); 956 if (kcmd == NULL) 957 return (kcmd); 958 959 bzero(kcmd, sizeof (*kcmd)); 960 961 if (irl != NULL) { 962 kcmd->flags = irl->irl_flags; 963 kcmd->ip_ver = AF_2_IPPROTO(irl->irl_ipversion); 964 kcmd->vip = irl->irl_vip; 965 kcmd->proto = irl->irl_proto; 966 kcmd->min_port = irl->irl_minport; 967 kcmd->max_port = irl->irl_maxport; 968 kcmd->algo = algo_lib2impl(irl->irl_algo); 969 kcmd->topo = topo_lib2impl(irl->irl_topo); 970 kcmd->sticky_mask = irl->irl_stickymask; 971 kcmd->nat_src_start = irl->irl_nat_src_start; 972 kcmd->nat_src_end = irl->irl_nat_src_end; 973 kcmd->conn_drain_timeout = irl->irl_conndrain; 974 kcmd->nat_expiry = irl->irl_nat_timeout; 975 kcmd->sticky_expiry = irl->irl_sticky_timeout; 976 (void) strlcpy(kcmd->name, irl->irl_name, 977 sizeof (kcmd->name)); 978 } 979 return (kcmd); 980 } 981 982 /* 983 * ncount is the next to be used index into (*kcmdp)->servers 984 */ 985 static ilb_status_t 986 adjust_srv_info_cmd(ilb_servers_info_cmd_t **kcmdp, int index) 987 { 988 ilb_servers_info_cmd_t *kcmd = *kcmdp; 989 size_t sz; 990 991 if (kcmd != NULL && kcmd->num_servers > index + 1) 992 return (ILB_STATUS_OK); 993 994 /* 995 * the first ilb_server_info_t is part of *kcmd, so 996 * by using index (which is one less than the total needed) here, 997 * we allocate exactly the amount we need. 998 */ 999 sz = sizeof (*kcmd) + (index * sizeof (ilb_server_info_t)); 1000 kcmd = (ilb_servers_info_cmd_t *)realloc(kcmd, sz); 1001 if (kcmd == NULL) 1002 return (ILB_STATUS_ENOMEM); 1003 1004 /* 1005 * we don't count the slot we newly allocated yet. 1006 */ 1007 kcmd->num_servers = index; 1008 *kcmdp = kcmd; 1009 1010 return (ILB_STATUS_OK); 1011 } 1012 1013 /* 1014 * this function adds all servers in srvlist to the kernel(!) rule 1015 * the name of which is passed as argument. 1016 */ 1017 static ilb_status_t 1018 i_update_ksrv_rules(char *name, ilbd_sg_t *sg, ilbd_rule_t *rl) 1019 { 1020 ilb_status_t rc; 1021 ilbd_srv_t *srvp; 1022 ilb_servers_info_cmd_t *kcmd = NULL; 1023 int i; 1024 1025 /* 1026 * If the servergroup doesn't have any servers associated with 1027 * it yet, there's nothing more to do here. 1028 */ 1029 if (sg->isg_srvcount == 0) 1030 return (ILB_STATUS_OK); 1031 1032 /* 1033 * walk the list of servers attached to this SG 1034 */ 1035 srvp = list_head(&sg->isg_srvlist); 1036 for (i = 0; srvp != NULL; srvp = list_next(&sg->isg_srvlist, srvp)) { 1037 rc = adjust_srv_info_cmd(&kcmd, i); 1038 if (rc != ILB_STATUS_OK) 1039 goto rollback_kcmd; 1040 1041 ILB_SGSRV_2_KSRV(&srvp->isv_srv, &kcmd->servers[i]); 1042 /* 1043 * "no port" means "copy rule's port" (for kernel rule) 1044 */ 1045 if (kcmd->servers[i].min_port == 0) { 1046 kcmd->servers[i].min_port = rl->irl_minport; 1047 kcmd->servers[i].max_port = rl->irl_maxport; 1048 } 1049 i++; 1050 } 1051 assert(kcmd != NULL); 1052 1053 kcmd->cmd = ILB_ADD_SERVERS; 1054 kcmd->num_servers = i; 1055 (void) strlcpy(kcmd->name, name, sizeof (kcmd->name)); 1056 1057 rc = do_ioctl(kcmd, 0); 1058 if (rc != ILB_STATUS_OK) 1059 goto rollback_kcmd; 1060 1061 for (i = 0; i < kcmd->num_servers; i++) { 1062 int e; 1063 1064 if ((e = kcmd->servers[i].err) != 0) { 1065 logerr("i_update_ksrv_rules " 1066 "ioctl indicates failure: %s", strerror(e)); 1067 rc = ilb_map_errno2ilbstat(e); 1068 /* 1069 * if adding even a single server failed, we need to 1070 * roll back the whole wad. We ignore any errors and 1071 * return the one that was returned by the first ioctl. 1072 */ 1073 kcmd->cmd = ILB_DEL_SERVERS; 1074 (void) do_ioctl(kcmd, 0); 1075 goto rollback_kcmd; 1076 } 1077 } 1078 1079 rollback_kcmd: 1080 free(kcmd); 1081 return (rc); 1082 } 1083 1084 /* convert a struct in6_addr to valstr */ 1085 void 1086 ilbd_ip_to_str(uint16_t ipversion, struct in6_addr *addr, char *valstr) 1087 { 1088 size_t vallen; 1089 ilb_ip_addr_t ipaddr; 1090 void *addrptr; 1091 1092 vallen = (ipversion == AF_INET) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN; 1093 1094 IP_COPY_IMPL_2_CLI(addr, &ipaddr); 1095 addrptr = (ipversion == AF_INET) ? 1096 (void *)&ipaddr.ia_v4 : (void *)&ipaddr.ia_v6; 1097 if (inet_ntop(ipversion, (void *)addrptr, valstr, vallen) == NULL) 1098 logerr("ilbd_ip_to_str: inet_ntop failed"); 1099 return; 1100 1101 } 1102 1103 ilb_status_t 1104 ilbd_create_rule(ilb_rule_info_t *rl, int ev_port, 1105 const struct passwd *ps, ucred_t *ucredp) 1106 { 1107 ilb_status_t rc; 1108 ilbd_rule_t *irl = NULL; 1109 ilbd_sg_t *sg; 1110 ilb_rule_cmd_t *kcmd = NULL; 1111 1112 if (ps != NULL) { 1113 if ((rc = ilbd_check_client_config_auth(ps)) != ILB_STATUS_OK) 1114 goto out; 1115 } 1116 1117 if (i_find_rule_byname(rl->rl_name) != NULL) { 1118 logdebug("ilbd_create_rule: rule %s" 1119 " already exists", rl->rl_name); 1120 ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, 1121 ILB_STATUS_DUP_RULE, ucredp); 1122 return (ILB_STATUS_DUP_RULE); 1123 } 1124 1125 sg = i_find_sg_byname(rl->rl_sgname); 1126 if (sg == NULL) { 1127 logdebug("ilbd_create_rule: rule %s uses non-existent" 1128 " servergroup name %s", rl->rl_name, rl->rl_sgname); 1129 ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, 1130 ILB_STATUS_SGUNAVAIL, ucredp); 1131 return (ILB_STATUS_SGUNAVAIL); 1132 } 1133 1134 if ((rc = ilbd_sg_check_rule_port(sg, rl)) != ILB_STATUS_OK) { 1135 ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, rc, ucredp); 1136 return (rc); 1137 } 1138 1139 /* allocs and copies contents of arg (if != NULL) into new rule */ 1140 irl = i_alloc_ilbd_rule(rl); 1141 if (irl == NULL) { 1142 ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, 1143 ILB_STATUS_ENOMEM, ucredp); 1144 return (ILB_STATUS_ENOMEM); 1145 } 1146 1147 /* make sure rule's IPversion (via vip) and SG's match */ 1148 if (sg->isg_srvcount > 0) { 1149 ilbd_srv_t *srv = list_head(&sg->isg_srvlist); 1150 int32_t r_af = rl->rl_ipversion; 1151 int32_t s_af = GET_AF(&srv->isv_addr); 1152 1153 if (r_af != s_af) { 1154 logdebug("address family mismatch with servergroup"); 1155 rc = ILB_STATUS_MISMATCHSG; 1156 goto out; 1157 } 1158 } 1159 irl->irl_sg = sg; 1160 1161 /* Try associating the rule with the given hc oject. */ 1162 if (RULE_HAS_HC(irl)) { 1163 if ((rc = ilbd_hc_associate_rule(irl, ev_port)) != 1164 ILB_STATUS_OK) 1165 goto out; 1166 } 1167 1168 /* 1169 * checks are done, now: 1170 * 1. create rule in kernel 1171 * 2. tell it about the backend server (which we maintain in SG) 1172 * 3. attach the rule in memory 1173 */ 1174 /* 1. */ 1175 /* allocs and copies contents of arg (if != NULL) into new rule */ 1176 kcmd = i_alloc_kernel_rule_cmd(irl); 1177 if (kcmd == NULL) { 1178 rc = ILB_STATUS_ENOMEM; 1179 goto rollback_hc; 1180 } 1181 kcmd->cmd = ILB_CREATE_RULE; 1182 1183 rc = do_ioctl(kcmd, 0); 1184 if (rc != ILB_STATUS_OK) 1185 goto rollback_kcmd; 1186 1187 /* 2. */ 1188 rc = i_update_ksrv_rules(kcmd->name, sg, irl); 1189 if (rc != ILB_STATUS_OK) 1190 goto rollback_kcmd; 1191 1192 /* 3. */ 1193 (void) i_attach_rule2sg(sg, irl); 1194 list_insert_tail(&ilbd_rule_hlist, irl); 1195 1196 if (ps != NULL) { 1197 rc = i_ilbd_save_rule(irl, ILBD_SCF_CREATE); 1198 if (rc != ILB_STATUS_OK) 1199 goto rollback_rule; 1200 } 1201 1202 free(kcmd); 1203 ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, 1204 ILB_STATUS_OK, ucredp); 1205 return (ILB_STATUS_OK); 1206 1207 rollback_rule: 1208 /* 1209 * ilbd_destroy_one_rule() also frees irl, as well as dissociate 1210 * rule and HC, so all we need to do afterwards is free the kcmd 1211 * and return. 1212 */ 1213 (void) ilbd_destroy_one_rule(irl); 1214 ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, rc, ucredp); 1215 free(kcmd); 1216 return (rc); 1217 1218 rollback_kcmd: 1219 free(kcmd); 1220 rollback_hc: 1221 /* Cannot fail since the rule is just associated with the hc object. */ 1222 if (RULE_HAS_HC(irl)) 1223 (void) ilbd_hc_dissociate_rule(irl); 1224 out: 1225 ilbd_audit_rule_event(NULL, rl, ILBD_CREATE_RULE, rc, ucredp); 1226 free(irl); 1227 return (rc); 1228 } 1229 1230 static uint32_t 1231 i_flags_d2k(int f) 1232 { 1233 uint32_t r = 0; 1234 1235 if (ILB_IS_SRV_ENABLED(f)) 1236 r |= ILB_SERVER_ENABLED; 1237 /* more as they are defined */ 1238 1239 return (r); 1240 } 1241 1242 /* 1243 * walk the list of rules and add srv to the *kernel* rule 1244 * (this is a list of rules hanging off of a server group) 1245 */ 1246 ilb_status_t 1247 i_add_srv2krules(list_t *rlist, ilb_sg_srv_t *srv, int ev_port) 1248 { 1249 ilb_status_t rc = ILB_STATUS_OK; 1250 ilbd_rule_t *rl, *del_rl; 1251 ilb_servers_info_cmd_t kcmd; 1252 ilb_servers_cmd_t del_kcmd; 1253 1254 kcmd.cmd = ILB_ADD_SERVERS; 1255 kcmd.num_servers = 1; 1256 kcmd.servers[0].err = 0; 1257 kcmd.servers[0].addr = srv->sgs_addr; 1258 kcmd.servers[0].flags = i_flags_d2k(srv->sgs_flags); 1259 (void) strlcpy(kcmd.servers[0].name, srv->sgs_srvID, 1260 sizeof (kcmd.servers[0].name)); 1261 1262 /* 1263 * a note about rollback: since we need to start rollback with the 1264 * current list element in some case, and with the previous one 1265 * in others, we must "go back" in this latter case before 1266 * we jump to the rollback code. 1267 */ 1268 for (rl = list_head(rlist); rl != NULL; rl = list_next(rlist, rl)) { 1269 (void) strlcpy(kcmd.name, rl->irl_name, sizeof (kcmd.name)); 1270 /* 1271 * sgs_minport == 0 means "no port specified"; this 1272 * indicates that the server matches anything the rule 1273 * provides. 1274 * NOTE: this can be different for different rules 1275 * using the same server group, therefore we don't modify 1276 * this information in the servergroup, but *only* in 1277 * the kernel's rule. 1278 */ 1279 if (srv->sgs_minport == 0) { 1280 kcmd.servers[0].min_port = rl->irl_minport; 1281 kcmd.servers[0].max_port = rl->irl_maxport; 1282 } else { 1283 kcmd.servers[0].min_port = srv->sgs_minport; 1284 kcmd.servers[0].max_port = srv->sgs_maxport; 1285 } 1286 rc = do_ioctl((void *)&kcmd, 0); 1287 if (rc != ILB_STATUS_OK) { 1288 logdebug("i_add_srv2krules: do_ioctl call failed"); 1289 del_rl = list_prev(rlist, rl); 1290 goto rollback; 1291 } 1292 1293 /* 1294 * if ioctl() returns != 0, it doesn't perform the copyout 1295 * necessary to indicate *which* server failed (we could be 1296 * adding more than one); therefore we must check this 1297 * 'err' field even if ioctl() returns 0. 1298 */ 1299 if (kcmd.servers[0].err != 0) { 1300 logerr("i_add_srv2krules: SIOCILB ioctl returned" 1301 " error %d", kcmd.servers[0].err); 1302 rc = ilb_map_errno2ilbstat(kcmd.servers[0].err); 1303 del_rl = list_prev(rlist, rl); 1304 goto rollback; 1305 } 1306 if (RULE_HAS_HC(rl)) { 1307 if ((rc = ilbd_hc_add_server(rl, srv, ev_port)) != 1308 ILB_STATUS_OK) { 1309 logerr("i_add_srv2krules: cannot start timer " 1310 " for rules %s server %s", rl->irl_name, 1311 srv->sgs_srvID); 1312 1313 del_rl = rl; 1314 goto rollback; 1315 } 1316 } 1317 } 1318 1319 return (rc); 1320 1321 rollback: 1322 /* 1323 * this is almost, but not quite, the same as i_rem_srv_frm_krules() 1324 * therefore we keep it seperate. 1325 */ 1326 del_kcmd.cmd = ILB_DEL_SERVERS; 1327 del_kcmd.num_servers = 1; 1328 del_kcmd.servers[0].addr = srv->sgs_addr; 1329 while (del_rl != NULL) { 1330 if (RULE_HAS_HC(del_rl)) 1331 (void) ilbd_hc_del_server(del_rl, srv); 1332 (void) strlcpy(del_kcmd.name, del_rl->irl_name, 1333 sizeof (del_kcmd.name)); 1334 (void) do_ioctl((void *)&del_kcmd, 0); 1335 del_rl = list_prev(rlist, del_rl); 1336 } 1337 1338 return (rc); 1339 } 1340 1341 /* 1342 * ev_port is only used for rollback purposes in this function 1343 */ 1344 ilb_status_t 1345 i_rem_srv_frm_krules(list_t *rlist, ilb_sg_srv_t *srv, int ev_port) 1346 { 1347 ilb_status_t rc = ILB_STATUS_OK; 1348 ilbd_rule_t *rl, *add_rl; 1349 ilb_servers_cmd_t kcmd; 1350 ilb_servers_info_cmd_t add_kcmd; 1351 1352 kcmd.cmd = ILB_DEL_SERVERS; 1353 kcmd.num_servers = 1; 1354 kcmd.servers[0].err = 0; 1355 kcmd.servers[0].addr = srv->sgs_addr; 1356 1357 for (rl = list_head(rlist); rl != NULL; rl = list_next(rlist, rl)) { 1358 (void) strlcpy(kcmd.name, rl->irl_name, sizeof (kcmd.name)); 1359 rc = do_ioctl((void *)&kcmd, 0); 1360 if (rc != ILB_STATUS_OK) { 1361 logdebug("i_rem_srv_frm_krules: do_ioctl" 1362 "call failed"); 1363 add_rl = list_prev(rlist, rl); 1364 goto rollback; 1365 } 1366 /* 1367 * if ioctl() returns != 0, it doesn't perform the copyout 1368 * necessary to indicate *which* server failed (we could be 1369 * removing more than one); therefore we must check this 1370 * 'err' field even if ioctl() returns 0. 1371 */ 1372 if (kcmd.servers[0].err != 0) { 1373 logerr("i_rem_srv_frm_krules: SIOCILB ioctl" 1374 " returned error %s", 1375 strerror(kcmd.servers[0].err)); 1376 rc = ilb_map_errno2ilbstat(kcmd.servers[0].err); 1377 add_rl = list_prev(rlist, rl); 1378 goto rollback; 1379 } 1380 if (RULE_HAS_HC(rl) && 1381 (rc = ilbd_hc_del_server(rl, srv)) != ILB_STATUS_OK) { 1382 logerr("i_rem_srv_frm_krules: cannot delete " 1383 "timer for rules %s server %s", rl->irl_name, 1384 srv->sgs_srvID); 1385 add_rl = rl; 1386 goto rollback; 1387 } 1388 } 1389 1390 return (rc); 1391 1392 rollback: 1393 /* Don't do roll back if ev_port == -1. */ 1394 if (ev_port == -1) 1395 return (rc); 1396 1397 add_kcmd.cmd = ILB_ADD_SERVERS; 1398 add_kcmd.num_servers = 1; 1399 add_kcmd.servers[0].err = 0; 1400 add_kcmd.servers[0].addr = srv->sgs_addr; 1401 add_kcmd.servers[0].flags = i_flags_d2k(srv->sgs_flags); 1402 (void) strlcpy(add_kcmd.servers[0].name, srv->sgs_srvID, 1403 sizeof (add_kcmd.servers[0].name)); 1404 while (add_rl != NULL) { 1405 if (srv->sgs_minport == 0) { 1406 add_kcmd.servers[0].min_port = add_rl->irl_minport; 1407 add_kcmd.servers[0].max_port = add_rl->irl_maxport; 1408 } else { 1409 add_kcmd.servers[0].min_port = srv->sgs_minport; 1410 add_kcmd.servers[0].max_port = srv->sgs_maxport; 1411 } 1412 if (RULE_HAS_HC(add_rl)) 1413 (void) ilbd_hc_add_server(add_rl, srv, ev_port); 1414 (void) strlcpy(add_kcmd.name, add_rl->irl_name, 1415 sizeof (add_kcmd.name)); 1416 (void) do_ioctl((void *)&add_kcmd, 0); 1417 add_rl = list_prev(rlist, add_rl); 1418 } 1419 1420 return (rc); 1421 } 1422