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
ilbd_show_nat_cleanup(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
ilbd_show_sticky_cleanup(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
ilbd_show_nat(void * cli,const ilb_comm_t * ic,uint32_t * rbuf,size_t * rbufsz)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
ilbd_show_sticky(void * cli,const ilb_comm_t * ic,uint32_t * rbuf,size_t * rbufsz)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