1*dbed73cbSSangeeta Misra /* 2*dbed73cbSSangeeta Misra * CDDL HEADER START 3*dbed73cbSSangeeta Misra * 4*dbed73cbSSangeeta Misra * The contents of this file are subject to the terms of the 5*dbed73cbSSangeeta Misra * Common Development and Distribution License (the "License"). 6*dbed73cbSSangeeta Misra * You may not use this file except in compliance with the License. 7*dbed73cbSSangeeta Misra * 8*dbed73cbSSangeeta Misra * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*dbed73cbSSangeeta Misra * or http://www.opensolaris.org/os/licensing. 10*dbed73cbSSangeeta Misra * See the License for the specific language governing permissions 11*dbed73cbSSangeeta Misra * and limitations under the License. 12*dbed73cbSSangeeta Misra * 13*dbed73cbSSangeeta Misra * When distributing Covered Code, include this CDDL HEADER in each 14*dbed73cbSSangeeta Misra * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*dbed73cbSSangeeta Misra * If applicable, add the following below this CDDL HEADER, with the 16*dbed73cbSSangeeta Misra * fields enclosed by brackets "[]" replaced with your own identifying 17*dbed73cbSSangeeta Misra * information: Portions Copyright [yyyy] [name of copyright owner] 18*dbed73cbSSangeeta Misra * 19*dbed73cbSSangeeta Misra * CDDL HEADER END 20*dbed73cbSSangeeta Misra */ 21*dbed73cbSSangeeta Misra 22*dbed73cbSSangeeta Misra /* 23*dbed73cbSSangeeta Misra * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*dbed73cbSSangeeta Misra * Use is subject to license terms. 25*dbed73cbSSangeeta Misra */ 26*dbed73cbSSangeeta Misra 27*dbed73cbSSangeeta Misra #include <sys/types.h> 28*dbed73cbSSangeeta Misra #include <libilb.h> 29*dbed73cbSSangeeta Misra #include <inet/ilb.h> 30*dbed73cbSSangeeta Misra #include <stddef.h> 31*dbed73cbSSangeeta Misra #include <stdlib.h> 32*dbed73cbSSangeeta Misra #include <strings.h> 33*dbed73cbSSangeeta Misra #include <errno.h> 34*dbed73cbSSangeeta Misra #include <assert.h> 35*dbed73cbSSangeeta Misra #include <macros.h> 36*dbed73cbSSangeeta Misra #include "libilb_impl.h" 37*dbed73cbSSangeeta Misra #include "ilbd.h" 38*dbed73cbSSangeeta Misra 39*dbed73cbSSangeeta Misra /* 40*dbed73cbSSangeeta Misra * We only allow one show nat/persist command running at any time. Note that 41*dbed73cbSSangeeta Misra * there is no lock for this since ilbd is single threaded. And we only care 42*dbed73cbSSangeeta Misra * about the pointer value of client, not its type. 43*dbed73cbSSangeeta Misra * 44*dbed73cbSSangeeta Misra * The following variables store the current client making the request. 45*dbed73cbSSangeeta Misra */ 46*dbed73cbSSangeeta Misra static void *nat_cur_cli; 47*dbed73cbSSangeeta Misra static void *sticky_cur_cli; 48*dbed73cbSSangeeta Misra 49*dbed73cbSSangeeta Misra /* Maximum number of NAT/sticky entries to request from kernel. */ 50*dbed73cbSSangeeta Misra #define NUM_ENTRIES 500 51*dbed73cbSSangeeta Misra 52*dbed73cbSSangeeta Misra /* 53*dbed73cbSSangeeta Misra * Clear the current requesting client. This will allow a new client 54*dbed73cbSSangeeta Misra * to make a request. 55*dbed73cbSSangeeta Misra */ 56*dbed73cbSSangeeta Misra void 57*dbed73cbSSangeeta Misra ilbd_show_nat_cleanup(void) 58*dbed73cbSSangeeta Misra { 59*dbed73cbSSangeeta Misra nat_cur_cli = NULL; 60*dbed73cbSSangeeta Misra } 61*dbed73cbSSangeeta Misra 62*dbed73cbSSangeeta Misra void 63*dbed73cbSSangeeta Misra ilbd_show_sticky_cleanup(void) 64*dbed73cbSSangeeta Misra { 65*dbed73cbSSangeeta Misra sticky_cur_cli = NULL; 66*dbed73cbSSangeeta Misra } 67*dbed73cbSSangeeta Misra 68*dbed73cbSSangeeta Misra /* 69*dbed73cbSSangeeta Misra * To show the kernel NAT table. 70*dbed73cbSSangeeta Misra * 71*dbed73cbSSangeeta Misra * cli: the client pointer making the request. 72*dbed73cbSSangeeta Misra * ic: the client request. 73*dbed73cbSSangeeta Misra * rbuf: reply buffer to be filled in. 74*dbed73cbSSangeeta Misra * rbufsz: reply buffer size. 75*dbed73cbSSangeeta Misra */ 76*dbed73cbSSangeeta Misra ilb_status_t 77*dbed73cbSSangeeta Misra ilbd_show_nat(void *cli, const ilb_comm_t *ic, uint32_t *rbuf, size_t *rbufsz) 78*dbed73cbSSangeeta Misra { 79*dbed73cbSSangeeta Misra ilb_show_info_t *req_si = (ilb_show_info_t *)&ic->ic_data; 80*dbed73cbSSangeeta Misra ilb_list_nat_cmd_t *kcmd; 81*dbed73cbSSangeeta Misra boolean_t start; 82*dbed73cbSSangeeta Misra size_t tmp_rbufsz, kbufsz; 83*dbed73cbSSangeeta Misra uint32_t max_num; 84*dbed73cbSSangeeta Misra ilb_status_t ret; 85*dbed73cbSSangeeta Misra int i; 86*dbed73cbSSangeeta Misra ilb_show_info_t *reply; 87*dbed73cbSSangeeta Misra ilb_nat_info_t *nat_ret; 88*dbed73cbSSangeeta Misra 89*dbed73cbSSangeeta Misra /* For new client request, start from the beginning of the table. */ 90*dbed73cbSSangeeta Misra if (nat_cur_cli == NULL) { 91*dbed73cbSSangeeta Misra nat_cur_cli = cli; 92*dbed73cbSSangeeta Misra start = B_TRUE; 93*dbed73cbSSangeeta Misra } else if (cli == nat_cur_cli) { 94*dbed73cbSSangeeta Misra /* 95*dbed73cbSSangeeta Misra * Another request from client. If the client does not 96*dbed73cbSSangeeta Misra * want to continue, reset the current client and reply OK. 97*dbed73cbSSangeeta Misra */ 98*dbed73cbSSangeeta Misra if (ic->ic_flags & ILB_COMM_END) { 99*dbed73cbSSangeeta Misra ilbd_show_nat_cleanup(); 100*dbed73cbSSangeeta Misra ilbd_reply_ok(rbuf, rbufsz); 101*dbed73cbSSangeeta Misra return (ILB_STATUS_OK); 102*dbed73cbSSangeeta Misra } 103*dbed73cbSSangeeta Misra start = B_FALSE; 104*dbed73cbSSangeeta Misra } else { 105*dbed73cbSSangeeta Misra /* A request is on-going, so reject a new client. */ 106*dbed73cbSSangeeta Misra return (ILB_STATUS_INPROGRESS); 107*dbed73cbSSangeeta Misra } 108*dbed73cbSSangeeta Misra 109*dbed73cbSSangeeta Misra tmp_rbufsz = *rbufsz; 110*dbed73cbSSangeeta Misra ilbd_reply_ok(rbuf, rbufsz); 111*dbed73cbSSangeeta Misra reply = (ilb_show_info_t *)&((ilb_comm_t *)rbuf)->ic_data; 112*dbed73cbSSangeeta Misra 113*dbed73cbSSangeeta Misra /* 114*dbed73cbSSangeeta Misra * Calculate the max number of ilb_nat_info_t can be fitted in the 115*dbed73cbSSangeeta Misra * reply. 116*dbed73cbSSangeeta Misra */ 117*dbed73cbSSangeeta Misra *rbufsz += sizeof (ilb_show_info_t *); 118*dbed73cbSSangeeta Misra tmp_rbufsz -= *rbufsz; 119*dbed73cbSSangeeta Misra max_num = tmp_rbufsz / sizeof (ilb_nat_info_t); 120*dbed73cbSSangeeta Misra 121*dbed73cbSSangeeta Misra /* 122*dbed73cbSSangeeta Misra * Calculate the exact number of entries we should request from kernel. 123*dbed73cbSSangeeta Misra */ 124*dbed73cbSSangeeta Misra max_num = min(req_si->sn_num, min(NUM_ENTRIES, max_num)); 125*dbed73cbSSangeeta Misra 126*dbed73cbSSangeeta Misra kbufsz = max_num * sizeof (ilb_nat_entry_t) + 127*dbed73cbSSangeeta Misra offsetof(ilb_list_nat_cmd_t, entries); 128*dbed73cbSSangeeta Misra if ((kcmd = malloc(kbufsz)) == NULL) { 129*dbed73cbSSangeeta Misra logdebug("ilbd_show_nat: malloc(cmd)"); 130*dbed73cbSSangeeta Misra ilbd_reply_err(rbuf, rbufsz, ILB_STATUS_ENOMEM); 131*dbed73cbSSangeeta Misra return (ILB_STATUS_ENOMEM); 132*dbed73cbSSangeeta Misra } 133*dbed73cbSSangeeta Misra 134*dbed73cbSSangeeta Misra kcmd->cmd = ILB_LIST_NAT_TABLE; 135*dbed73cbSSangeeta Misra kcmd->flags = start ? ILB_LIST_BEGIN : ILB_LIST_CONT; 136*dbed73cbSSangeeta Misra kcmd->num_nat = max_num; 137*dbed73cbSSangeeta Misra if ((ret = do_ioctl(kcmd, kbufsz)) != ILB_STATUS_OK) { 138*dbed73cbSSangeeta Misra logperror("ilbd_show_nat: ioctl(ILB_LIST_NAT_TABLE)"); 139*dbed73cbSSangeeta Misra ilbd_reply_err(rbuf, rbufsz, ret); 140*dbed73cbSSangeeta Misra free(kcmd); 141*dbed73cbSSangeeta Misra return (ret); 142*dbed73cbSSangeeta Misra } 143*dbed73cbSSangeeta Misra 144*dbed73cbSSangeeta Misra reply->sn_num = kcmd->num_nat; 145*dbed73cbSSangeeta Misra *rbufsz += reply->sn_num * sizeof (ilb_nat_info_t); 146*dbed73cbSSangeeta Misra 147*dbed73cbSSangeeta Misra /* 148*dbed73cbSSangeeta Misra * It is the end of table, let the client know. And the transaction 149*dbed73cbSSangeeta Misra * is done. 150*dbed73cbSSangeeta Misra */ 151*dbed73cbSSangeeta Misra if (kcmd->flags & ILB_LIST_END) { 152*dbed73cbSSangeeta Misra nat_cur_cli = NULL; 153*dbed73cbSSangeeta Misra } else { 154*dbed73cbSSangeeta Misra /* 155*dbed73cbSSangeeta Misra * ilbd_reply_ok() sets ic_flags to ILB_COMM_END by default. 156*dbed73cbSSangeeta Misra * Need to clear it here. 157*dbed73cbSSangeeta Misra */ 158*dbed73cbSSangeeta Misra ((ilb_comm_t *)rbuf)->ic_flags = 0; 159*dbed73cbSSangeeta Misra } 160*dbed73cbSSangeeta Misra 161*dbed73cbSSangeeta Misra nat_ret = (ilb_nat_info_t *)&reply->sn_data; 162*dbed73cbSSangeeta Misra 163*dbed73cbSSangeeta Misra for (i = 0; i < kcmd->num_nat; i++) { 164*dbed73cbSSangeeta Misra ilb_nat_entry_t *nat; 165*dbed73cbSSangeeta Misra 166*dbed73cbSSangeeta Misra nat = &kcmd->entries[i]; 167*dbed73cbSSangeeta Misra 168*dbed73cbSSangeeta Misra nat_ret->nat_proto = nat->proto; 169*dbed73cbSSangeeta Misra 170*dbed73cbSSangeeta Misra nat_ret->nat_in_local = nat->in_local; 171*dbed73cbSSangeeta Misra nat_ret->nat_in_global = nat->in_global; 172*dbed73cbSSangeeta Misra nat_ret->nat_out_local = nat->out_local; 173*dbed73cbSSangeeta Misra nat_ret->nat_out_global = nat->out_global; 174*dbed73cbSSangeeta Misra 175*dbed73cbSSangeeta Misra nat_ret->nat_in_local_port = nat->in_local_port; 176*dbed73cbSSangeeta Misra nat_ret->nat_in_global_port = nat->in_global_port; 177*dbed73cbSSangeeta Misra nat_ret->nat_out_local_port = nat->out_local_port; 178*dbed73cbSSangeeta Misra nat_ret->nat_out_global_port = nat->out_global_port; 179*dbed73cbSSangeeta Misra 180*dbed73cbSSangeeta Misra nat_ret++; 181*dbed73cbSSangeeta Misra } 182*dbed73cbSSangeeta Misra 183*dbed73cbSSangeeta Misra end: 184*dbed73cbSSangeeta Misra free(kcmd); 185*dbed73cbSSangeeta Misra return (ret); 186*dbed73cbSSangeeta Misra } 187*dbed73cbSSangeeta Misra 188*dbed73cbSSangeeta Misra /* 189*dbed73cbSSangeeta Misra * To show the kernel sticky table. 190*dbed73cbSSangeeta Misra * 191*dbed73cbSSangeeta Misra * cli: the client pointer making the request. 192*dbed73cbSSangeeta Misra * req_si: information about the show-persist request. 193*dbed73cbSSangeeta Misra * rbuf: reply buffer to be filled in. 194*dbed73cbSSangeeta Misra * rbufsz: reply buffer size. 195*dbed73cbSSangeeta Misra */ 196*dbed73cbSSangeeta Misra ilb_status_t 197*dbed73cbSSangeeta Misra ilbd_show_sticky(void *cli, const ilb_comm_t *ic, uint32_t *rbuf, 198*dbed73cbSSangeeta Misra size_t *rbufsz) 199*dbed73cbSSangeeta Misra { 200*dbed73cbSSangeeta Misra ilb_show_info_t *req_si = (ilb_show_info_t *)&ic->ic_data; 201*dbed73cbSSangeeta Misra ilb_list_sticky_cmd_t *kcmd; 202*dbed73cbSSangeeta Misra boolean_t start; 203*dbed73cbSSangeeta Misra size_t tmp_rbufsz, kbufsz; 204*dbed73cbSSangeeta Misra uint32_t max_num; 205*dbed73cbSSangeeta Misra ilb_status_t ret; 206*dbed73cbSSangeeta Misra int i; 207*dbed73cbSSangeeta Misra ilb_show_info_t *reply; 208*dbed73cbSSangeeta Misra ilb_persist_info_t *st_ret; 209*dbed73cbSSangeeta Misra 210*dbed73cbSSangeeta Misra /* For new client request, start from the beginning of the table. */ 211*dbed73cbSSangeeta Misra if (sticky_cur_cli == NULL) { 212*dbed73cbSSangeeta Misra sticky_cur_cli = cli; 213*dbed73cbSSangeeta Misra start = B_TRUE; 214*dbed73cbSSangeeta Misra } else if (cli == sticky_cur_cli) { 215*dbed73cbSSangeeta Misra /* 216*dbed73cbSSangeeta Misra * Another request from client. If the client does not 217*dbed73cbSSangeeta Misra * want to continue, reset the current client and reply OK. 218*dbed73cbSSangeeta Misra */ 219*dbed73cbSSangeeta Misra if (ic->ic_flags & ILB_COMM_END) { 220*dbed73cbSSangeeta Misra ilbd_show_sticky_cleanup(); 221*dbed73cbSSangeeta Misra ilbd_reply_ok(rbuf, rbufsz); 222*dbed73cbSSangeeta Misra return (ILB_STATUS_OK); 223*dbed73cbSSangeeta Misra } 224*dbed73cbSSangeeta Misra start = B_FALSE; 225*dbed73cbSSangeeta Misra } else { 226*dbed73cbSSangeeta Misra /* A request is on-going, so reject a new client. */ 227*dbed73cbSSangeeta Misra return (ILB_STATUS_INPROGRESS); 228*dbed73cbSSangeeta Misra } 229*dbed73cbSSangeeta Misra 230*dbed73cbSSangeeta Misra tmp_rbufsz = *rbufsz; 231*dbed73cbSSangeeta Misra ilbd_reply_ok(rbuf, rbufsz); 232*dbed73cbSSangeeta Misra reply = (ilb_show_info_t *)&((ilb_comm_t *)rbuf)->ic_data; 233*dbed73cbSSangeeta Misra 234*dbed73cbSSangeeta Misra /* 235*dbed73cbSSangeeta Misra * Calculate the max number of ilb_persist_info_t can be fitted in the 236*dbed73cbSSangeeta Misra * reply. 237*dbed73cbSSangeeta Misra */ 238*dbed73cbSSangeeta Misra *rbufsz += sizeof (ilb_show_info_t *); 239*dbed73cbSSangeeta Misra tmp_rbufsz -= *rbufsz; 240*dbed73cbSSangeeta Misra max_num = tmp_rbufsz / sizeof (ilb_persist_info_t); 241*dbed73cbSSangeeta Misra 242*dbed73cbSSangeeta Misra /* 243*dbed73cbSSangeeta Misra * Calculate the exact number of entries we should request from kernel. 244*dbed73cbSSangeeta Misra */ 245*dbed73cbSSangeeta Misra max_num = min(req_si->sn_num, min(NUM_ENTRIES, max_num)); 246*dbed73cbSSangeeta Misra 247*dbed73cbSSangeeta Misra kbufsz = max_num * sizeof (ilb_sticky_entry_t) + 248*dbed73cbSSangeeta Misra offsetof(ilb_list_sticky_cmd_t, entries); 249*dbed73cbSSangeeta Misra if ((kcmd = malloc(kbufsz)) == NULL) { 250*dbed73cbSSangeeta Misra logdebug("ilbd_show_nat: malloc(cmd)"); 251*dbed73cbSSangeeta Misra ilbd_reply_err(rbuf, rbufsz, ILB_STATUS_ENOMEM); 252*dbed73cbSSangeeta Misra return (ILB_STATUS_ENOMEM); 253*dbed73cbSSangeeta Misra } 254*dbed73cbSSangeeta Misra 255*dbed73cbSSangeeta Misra kcmd->cmd = ILB_LIST_STICKY_TABLE; 256*dbed73cbSSangeeta Misra kcmd->flags = start ? ILB_LIST_BEGIN : ILB_LIST_CONT; 257*dbed73cbSSangeeta Misra kcmd->num_sticky = max_num; 258*dbed73cbSSangeeta Misra if ((ret = do_ioctl(kcmd, kbufsz)) != ILB_STATUS_OK) { 259*dbed73cbSSangeeta Misra logperror("ilbd_show_nat: ioctl(ILB_LIST_STICKY_TABLE)"); 260*dbed73cbSSangeeta Misra ilbd_reply_err(rbuf, rbufsz, ret); 261*dbed73cbSSangeeta Misra free(kcmd); 262*dbed73cbSSangeeta Misra return (ret); 263*dbed73cbSSangeeta Misra } 264*dbed73cbSSangeeta Misra 265*dbed73cbSSangeeta Misra reply->sn_num = kcmd->num_sticky; 266*dbed73cbSSangeeta Misra *rbufsz += reply->sn_num * sizeof (ilb_persist_info_t); 267*dbed73cbSSangeeta Misra 268*dbed73cbSSangeeta Misra if (kcmd->flags & ILB_LIST_END) { 269*dbed73cbSSangeeta Misra sticky_cur_cli = NULL; 270*dbed73cbSSangeeta Misra } else { 271*dbed73cbSSangeeta Misra /* 272*dbed73cbSSangeeta Misra * ilbd_reply_ok() sets ic_flags to ILB_COMM_END by default. 273*dbed73cbSSangeeta Misra * Need to clear it here. 274*dbed73cbSSangeeta Misra */ 275*dbed73cbSSangeeta Misra ((ilb_comm_t *)rbuf)->ic_flags = 0; 276*dbed73cbSSangeeta Misra } 277*dbed73cbSSangeeta Misra 278*dbed73cbSSangeeta Misra st_ret = (ilb_persist_info_t *)&reply->sn_data; 279*dbed73cbSSangeeta Misra 280*dbed73cbSSangeeta Misra for (i = 0; i < kcmd->num_sticky; i++) { 281*dbed73cbSSangeeta Misra ilb_sticky_entry_t *st; 282*dbed73cbSSangeeta Misra 283*dbed73cbSSangeeta Misra st = &kcmd->entries[i]; 284*dbed73cbSSangeeta Misra 285*dbed73cbSSangeeta Misra (void) strlcpy(st_ret->persist_rule_name, st->rule_name, 286*dbed73cbSSangeeta Misra ILB_NAMESZ); 287*dbed73cbSSangeeta Misra st_ret->persist_req_addr = st->req_addr; 288*dbed73cbSSangeeta Misra st_ret->persist_srv_addr = st->srv_addr; 289*dbed73cbSSangeeta Misra st_ret++; 290*dbed73cbSSangeeta Misra } 291*dbed73cbSSangeeta Misra 292*dbed73cbSSangeeta Misra end: 293*dbed73cbSSangeeta Misra free(kcmd); 294*dbed73cbSSangeeta Misra return (ret); 295*dbed73cbSSangeeta Misra } 296