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