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
i_setup_sg_hlist(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 *
i_ilbd_alloc_sg(char * name)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
i_ilbd_save_sg(ilbd_sg_t * d_sg,ilbd_scf_cmd_t scf_cmd,const char * prop_name,char * valstr)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
i_attach_rule2sg(ilbd_sg_t * sg,ilbd_rule_t * irl)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
i_ilbd_free_sg(ilbd_sg_t * sg)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 *
i_find_sg_byname(const char * name)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
ilbd_audit_server_event(audit_sg_event_data_t * data,ilbd_cmd_t cmd,ilb_status_t rc,ucred_t * ucredp)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
ilbd_destroy_sg(const char * sg_name,const struct passwd * ps,ucred_t * ucredp)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
ilbd_create_sg(ilb_sg_info_t * sg,int ev_port,const struct passwd * ps,ucred_t * ucredp)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
i_test_and_insert(ilbd_srv_t * tsrv,ilbd_srv_t * lsrv,list_t * srvlist)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
i_add_srv2sg(ilbd_sg_t * dsg,ilb_sg_srv_t * srv,ilbd_srv_t ** ret_srv)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
i_ilbd_alloc_srvID(ilbd_sg_t * sg,int32_t * set_id)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
i_ilbd_free_srvID(ilbd_sg_t * sg,int32_t id)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
fill_audit_record(ilb_sg_info_t * sg,audit_sg_event_data_t * audit_sg_data,ilbd_cmd_t cmd,ilb_status_t rc,ucred_t * ucredp)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
ilbd_add_server_to_group(ilb_sg_info_t * sg_info,int ev_port,const struct passwd * ps,ucred_t * ucredp)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
i_match_srvID(ilb_sg_srv_t * sg_srv,ilbd_srv_t * lsrv)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
ilbd_sg_check_rule_port(ilbd_sg_t * sg,ilb_rule_info_t * rl)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
i_match_srvIP(ilb_sg_srv_t * sg_srv,ilbd_srv_t * lsrv)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 *
i_find_srv(list_t * srvlist,ilb_sg_srv_t * sg_srv,int cmpmode)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
i_delete_srv(ilbd_sg_t * sg,ilbd_srv_t * srv,int ev_port)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
ilbd_rem_server_from_group(ilb_sg_info_t * sg_info,int ev_port,const struct passwd * ps,ucred_t * ucredp)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
ilbd_retrieve_names(ilbd_cmd_t cmd,uint32_t * rbuf,size_t * rbufsz)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
ilbd_retrieve_sg_hosts(const char * sg_name,uint32_t * rbuf,size_t * rbufsz)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
i_srvcmd_d2k(ilbd_srv_status_ind_t dcmd)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
ilbd_k_Xable_server(const struct in6_addr * addr,const char * rlname,ilbd_srv_status_ind_t cmd)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
ilbd_Xable_server(ilb_sg_info_t * sg,const struct passwd * ps,ilbd_srv_status_ind_t cmd,ucred_t * ucredp)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
ilbd_disable_server(ilb_sg_info_t * sg,const struct passwd * ps,ucred_t * ucredp)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
ilbd_enable_server(ilb_sg_info_t * sg,const struct passwd * ps,ucred_t * ucredp)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
ilbd_address_to_srvID(ilb_sg_info_t * sg,uint32_t * rbuf,size_t * rbufsz)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
ilbd_srvID_to_address(ilb_sg_info_t * sg,uint32_t * rbuf,size_t * rbufsz)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
ilberror2auditerror(ilb_status_t rc)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