xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/ilbadm/ilbadm_subr.c (revision 10946:324bab2b3370)
1*10946SSangeeta.Misra@Sun.COM /*
2*10946SSangeeta.Misra@Sun.COM  * CDDL HEADER START
3*10946SSangeeta.Misra@Sun.COM  *
4*10946SSangeeta.Misra@Sun.COM  * The contents of this file are subject to the terms of the
5*10946SSangeeta.Misra@Sun.COM  * Common Development and Distribution License (the "License").
6*10946SSangeeta.Misra@Sun.COM  * You may not use this file except in compliance with the License.
7*10946SSangeeta.Misra@Sun.COM  *
8*10946SSangeeta.Misra@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10946SSangeeta.Misra@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*10946SSangeeta.Misra@Sun.COM  * See the License for the specific language governing permissions
11*10946SSangeeta.Misra@Sun.COM  * and limitations under the License.
12*10946SSangeeta.Misra@Sun.COM  *
13*10946SSangeeta.Misra@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*10946SSangeeta.Misra@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10946SSangeeta.Misra@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*10946SSangeeta.Misra@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*10946SSangeeta.Misra@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*10946SSangeeta.Misra@Sun.COM  *
19*10946SSangeeta.Misra@Sun.COM  * CDDL HEADER END
20*10946SSangeeta.Misra@Sun.COM  */
21*10946SSangeeta.Misra@Sun.COM 
22*10946SSangeeta.Misra@Sun.COM /*
23*10946SSangeeta.Misra@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*10946SSangeeta.Misra@Sun.COM  * Use is subject to license terms.
25*10946SSangeeta.Misra@Sun.COM  */
26*10946SSangeeta.Misra@Sun.COM 
27*10946SSangeeta.Misra@Sun.COM #include <stdio.h>
28*10946SSangeeta.Misra@Sun.COM #include <unistd.h>
29*10946SSangeeta.Misra@Sun.COM #include <stdlib.h>
30*10946SSangeeta.Misra@Sun.COM #include <strings.h>
31*10946SSangeeta.Misra@Sun.COM #include <sys/types.h>
32*10946SSangeeta.Misra@Sun.COM #include <sys/socket.h>
33*10946SSangeeta.Misra@Sun.COM #include <netinet/in.h>
34*10946SSangeeta.Misra@Sun.COM #include <arpa/inet.h>
35*10946SSangeeta.Misra@Sun.COM #include <netdb.h>
36*10946SSangeeta.Misra@Sun.COM #include <errno.h>
37*10946SSangeeta.Misra@Sun.COM #include <ctype.h>
38*10946SSangeeta.Misra@Sun.COM #include <assert.h>
39*10946SSangeeta.Misra@Sun.COM #include <limits.h>
40*10946SSangeeta.Misra@Sun.COM #include <libilb.h>
41*10946SSangeeta.Misra@Sun.COM #include <libilb_impl.h>
42*10946SSangeeta.Misra@Sun.COM #include "ilbadm.h"
43*10946SSangeeta.Misra@Sun.COM 
44*10946SSangeeta.Misra@Sun.COM #define	PORT_SEP	':'
45*10946SSangeeta.Misra@Sun.COM 
46*10946SSangeeta.Misra@Sun.COM typedef enum {
47*10946SSangeeta.Misra@Sun.COM 	numeric = 1,
48*10946SSangeeta.Misra@Sun.COM 	non_numeric
49*10946SSangeeta.Misra@Sun.COM } addr_type_t;
50*10946SSangeeta.Misra@Sun.COM 
51*10946SSangeeta.Misra@Sun.COM ilbadm_val_type_t algo_types[] = {
52*10946SSangeeta.Misra@Sun.COM 	{(int)ILB_ALG_ROUNDROBIN, "roundrobin", "rr"},
53*10946SSangeeta.Misra@Sun.COM 	{(int)ILB_ALG_HASH_IP, "hash-ip", "hip"},
54*10946SSangeeta.Misra@Sun.COM 	{(int)ILB_ALG_HASH_IP_SPORT, "hash-ip-port", "hipp"},
55*10946SSangeeta.Misra@Sun.COM 	{(int)ILB_ALG_HASH_IP_VIP, "hash-ip-vip", "hipv"},
56*10946SSangeeta.Misra@Sun.COM 	{ILBD_BAD_VAL, NULL, NULL}
57*10946SSangeeta.Misra@Sun.COM };
58*10946SSangeeta.Misra@Sun.COM 
59*10946SSangeeta.Misra@Sun.COM ilbadm_val_type_t topo_types[] = {
60*10946SSangeeta.Misra@Sun.COM 	{(int)ILB_TOPO_DSR, "DSR", "d"},
61*10946SSangeeta.Misra@Sun.COM 	{(int)ILB_TOPO_NAT, "NAT", "n"},
62*10946SSangeeta.Misra@Sun.COM 	{(int)ILB_TOPO_HALF_NAT, "HALF-NAT", "h"},
63*10946SSangeeta.Misra@Sun.COM 	{ILBD_BAD_VAL, NULL, NULL}
64*10946SSangeeta.Misra@Sun.COM };
65*10946SSangeeta.Misra@Sun.COM 
66*10946SSangeeta.Misra@Sun.COM void
ip2str(ilb_ip_addr_t * ip,char * buf,size_t sz,int flags)67*10946SSangeeta.Misra@Sun.COM ip2str(ilb_ip_addr_t *ip, char *buf, size_t sz, int flags)
68*10946SSangeeta.Misra@Sun.COM {
69*10946SSangeeta.Misra@Sun.COM 	int	len;
70*10946SSangeeta.Misra@Sun.COM 
71*10946SSangeeta.Misra@Sun.COM 	switch (ip->ia_af) {
72*10946SSangeeta.Misra@Sun.COM 	case AF_INET:
73*10946SSangeeta.Misra@Sun.COM 		if (*(uint32_t *)&ip->ia_v4 == 0)
74*10946SSangeeta.Misra@Sun.COM 			buf[0] = '\0';
75*10946SSangeeta.Misra@Sun.COM 		else
76*10946SSangeeta.Misra@Sun.COM 			(void) inet_ntop(AF_INET, (void *)&ip->ia_v4, buf, sz);
77*10946SSangeeta.Misra@Sun.COM 		break;
78*10946SSangeeta.Misra@Sun.COM 	case AF_INET6:
79*10946SSangeeta.Misra@Sun.COM 		if (IN6_IS_ADDR_UNSPECIFIED(&ip->ia_v6)) {
80*10946SSangeeta.Misra@Sun.COM 			buf[0] = '\0';
81*10946SSangeeta.Misra@Sun.COM 			break;
82*10946SSangeeta.Misra@Sun.COM 		}
83*10946SSangeeta.Misra@Sun.COM 		if (!(flags & V6_ADDRONLY))
84*10946SSangeeta.Misra@Sun.COM 			*buf++ = '[';
85*10946SSangeeta.Misra@Sun.COM 		sz--;
86*10946SSangeeta.Misra@Sun.COM 		(void) inet_ntop(ip->ia_af, (void *)&ip->ia_v6, buf, sz);
87*10946SSangeeta.Misra@Sun.COM 		if (!(flags & V6_ADDRONLY)) {
88*10946SSangeeta.Misra@Sun.COM 			len = strlen(buf);
89*10946SSangeeta.Misra@Sun.COM 			buf[len] = ']';
90*10946SSangeeta.Misra@Sun.COM 			buf[++len] = '\0';
91*10946SSangeeta.Misra@Sun.COM 		}
92*10946SSangeeta.Misra@Sun.COM 		break;
93*10946SSangeeta.Misra@Sun.COM 	default: buf[0] = '\0';
94*10946SSangeeta.Misra@Sun.COM 	}
95*10946SSangeeta.Misra@Sun.COM }
96*10946SSangeeta.Misra@Sun.COM 
97*10946SSangeeta.Misra@Sun.COM char *
i_str_from_val(int val,ilbadm_val_type_t * types)98*10946SSangeeta.Misra@Sun.COM i_str_from_val(int val, ilbadm_val_type_t *types)
99*10946SSangeeta.Misra@Sun.COM {
100*10946SSangeeta.Misra@Sun.COM 	ilbadm_val_type_t	*v;
101*10946SSangeeta.Misra@Sun.COM 
102*10946SSangeeta.Misra@Sun.COM 	for (v = types; v->v_type != ILBD_BAD_VAL; v++) {
103*10946SSangeeta.Misra@Sun.COM 		if (v->v_type == val)
104*10946SSangeeta.Misra@Sun.COM 			break;
105*10946SSangeeta.Misra@Sun.COM 	}
106*10946SSangeeta.Misra@Sun.COM 	/* we return this in all cases */
107*10946SSangeeta.Misra@Sun.COM 	return (v->v_name);
108*10946SSangeeta.Misra@Sun.COM }
109*10946SSangeeta.Misra@Sun.COM 
110*10946SSangeeta.Misra@Sun.COM int
i_val_from_str(char * name,ilbadm_val_type_t * types)111*10946SSangeeta.Misra@Sun.COM i_val_from_str(char *name, ilbadm_val_type_t *types)
112*10946SSangeeta.Misra@Sun.COM {
113*10946SSangeeta.Misra@Sun.COM 	ilbadm_val_type_t	*v;
114*10946SSangeeta.Misra@Sun.COM 
115*10946SSangeeta.Misra@Sun.COM 	for (v = types; v->v_type != ILBD_BAD_VAL; v++) {
116*10946SSangeeta.Misra@Sun.COM 		if (strncasecmp(name, v->v_name, sizeof (v->v_name)) == 0 ||
117*10946SSangeeta.Misra@Sun.COM 		    strncasecmp(name, v->v_alias, sizeof (v->v_alias)) == 0)
118*10946SSangeeta.Misra@Sun.COM 			break;
119*10946SSangeeta.Misra@Sun.COM 	}
120*10946SSangeeta.Misra@Sun.COM 	/* we return this in all cases */
121*10946SSangeeta.Misra@Sun.COM 	return (v->v_type);
122*10946SSangeeta.Misra@Sun.COM }
123*10946SSangeeta.Misra@Sun.COM 
124*10946SSangeeta.Misra@Sun.COM ilbadm_key_code_t
i_match_key(char * key,ilbadm_key_name_t * keylist)125*10946SSangeeta.Misra@Sun.COM i_match_key(char *key, ilbadm_key_name_t *keylist)
126*10946SSangeeta.Misra@Sun.COM {
127*10946SSangeeta.Misra@Sun.COM 	ilbadm_key_name_t	*t_key;
128*10946SSangeeta.Misra@Sun.COM 
129*10946SSangeeta.Misra@Sun.COM 	for (t_key = keylist; t_key->k_key != ILB_KEY_BAD; t_key++) {
130*10946SSangeeta.Misra@Sun.COM 		if (strncasecmp(key, t_key->k_name,
131*10946SSangeeta.Misra@Sun.COM 		    sizeof (t_key->k_name)) == 0 ||
132*10946SSangeeta.Misra@Sun.COM 		    strncasecmp(key, t_key->k_alias,
133*10946SSangeeta.Misra@Sun.COM 		    sizeof (t_key->k_alias)) == 0)
134*10946SSangeeta.Misra@Sun.COM 			break;
135*10946SSangeeta.Misra@Sun.COM 	}
136*10946SSangeeta.Misra@Sun.COM 	return (t_key->k_key);
137*10946SSangeeta.Misra@Sun.COM }
138*10946SSangeeta.Misra@Sun.COM 
139*10946SSangeeta.Misra@Sun.COM /*
140*10946SSangeeta.Misra@Sun.COM  * try to match:
141*10946SSangeeta.Misra@Sun.COM  * 1) IPv4 address
142*10946SSangeeta.Misra@Sun.COM  * 2) IPv6 address
143*10946SSangeeta.Misra@Sun.COM  * 3) a hostname
144*10946SSangeeta.Misra@Sun.COM  */
145*10946SSangeeta.Misra@Sun.COM static ilbadm_status_t
i_match_onehost(const char * val,ilb_ip_addr_t * ip,addr_type_t * a_type)146*10946SSangeeta.Misra@Sun.COM i_match_onehost(const char *val, ilb_ip_addr_t *ip, addr_type_t *a_type)
147*10946SSangeeta.Misra@Sun.COM {
148*10946SSangeeta.Misra@Sun.COM 	struct addrinfo *ai = NULL;
149*10946SSangeeta.Misra@Sun.COM 	struct addrinfo hints;
150*10946SSangeeta.Misra@Sun.COM 	addr_type_t	at = numeric;
151*10946SSangeeta.Misra@Sun.COM 
152*10946SSangeeta.Misra@Sun.COM 	(void) memset((void *)&hints, 0, sizeof (hints));
153*10946SSangeeta.Misra@Sun.COM 	hints.ai_flags |= AI_NUMERICHOST;
154*10946SSangeeta.Misra@Sun.COM 
155*10946SSangeeta.Misra@Sun.COM 	/*
156*10946SSangeeta.Misra@Sun.COM 	 * if *a_type == numeric, we only want to check whether this
157*10946SSangeeta.Misra@Sun.COM 	 * is a (valid) numeric IP address. If we do and it is NOT,
158*10946SSangeeta.Misra@Sun.COM 	 * we return _ENOENT.
159*10946SSangeeta.Misra@Sun.COM 	 */
160*10946SSangeeta.Misra@Sun.COM 	if (getaddrinfo(val, NULL, &hints, &ai) != 0) {
161*10946SSangeeta.Misra@Sun.COM 		if (a_type != NULL && (*a_type == numeric))
162*10946SSangeeta.Misra@Sun.COM 			return (ILBADM_INVAL_ADDR);
163*10946SSangeeta.Misra@Sun.COM 
164*10946SSangeeta.Misra@Sun.COM 		at = non_numeric;
165*10946SSangeeta.Misra@Sun.COM 		if (getaddrinfo(val, NULL, NULL, &ai) != 0)
166*10946SSangeeta.Misra@Sun.COM 			return (ILBADM_INVAL_ADDR);
167*10946SSangeeta.Misra@Sun.COM 	}
168*10946SSangeeta.Misra@Sun.COM 
169*10946SSangeeta.Misra@Sun.COM 	ip->ia_af = ai->ai_family;
170*10946SSangeeta.Misra@Sun.COM 	switch (ip->ia_af) {
171*10946SSangeeta.Misra@Sun.COM 	case AF_INET: {
172*10946SSangeeta.Misra@Sun.COM 		struct sockaddr_in	sa;
173*10946SSangeeta.Misra@Sun.COM 
174*10946SSangeeta.Misra@Sun.COM 		assert(ai->ai_addrlen == sizeof (sa));
175*10946SSangeeta.Misra@Sun.COM 		(void) memcpy(&sa, ai->ai_addr, sizeof (sa));
176*10946SSangeeta.Misra@Sun.COM 		ip->ia_v4 = sa.sin_addr;
177*10946SSangeeta.Misra@Sun.COM 		break;
178*10946SSangeeta.Misra@Sun.COM 	}
179*10946SSangeeta.Misra@Sun.COM 	case AF_INET6: {
180*10946SSangeeta.Misra@Sun.COM 		struct sockaddr_in6	sa;
181*10946SSangeeta.Misra@Sun.COM 
182*10946SSangeeta.Misra@Sun.COM 		assert(ai->ai_addrlen == sizeof (sa));
183*10946SSangeeta.Misra@Sun.COM 		(void) memcpy(&sa, ai->ai_addr, sizeof (sa));
184*10946SSangeeta.Misra@Sun.COM 		ip->ia_v6 = sa.sin6_addr;
185*10946SSangeeta.Misra@Sun.COM 		break;
186*10946SSangeeta.Misra@Sun.COM 	}
187*10946SSangeeta.Misra@Sun.COM 	default:
188*10946SSangeeta.Misra@Sun.COM 		return (ILBADM_INVAL_AF);
189*10946SSangeeta.Misra@Sun.COM 		break;
190*10946SSangeeta.Misra@Sun.COM 	}
191*10946SSangeeta.Misra@Sun.COM 
192*10946SSangeeta.Misra@Sun.COM 	if (a_type != NULL)
193*10946SSangeeta.Misra@Sun.COM 		*a_type = at;
194*10946SSangeeta.Misra@Sun.COM 	return (ILBADM_OK);
195*10946SSangeeta.Misra@Sun.COM }
196*10946SSangeeta.Misra@Sun.COM 
197*10946SSangeeta.Misra@Sun.COM static ilbadm_status_t
i_store_serverID(void * store,char * val)198*10946SSangeeta.Misra@Sun.COM i_store_serverID(void *store, char *val)
199*10946SSangeeta.Misra@Sun.COM {
200*10946SSangeeta.Misra@Sun.COM 	ilbadm_servnode_t	*s = (ilbadm_servnode_t *)store;
201*10946SSangeeta.Misra@Sun.COM 	ilb_server_data_t	*sn = &s->s_spec;
202*10946SSangeeta.Misra@Sun.COM 
203*10946SSangeeta.Misra@Sun.COM 	/*
204*10946SSangeeta.Misra@Sun.COM 	 * we shouldn't need to check for length here, as a name that's
205*10946SSangeeta.Misra@Sun.COM 	 * too long won't exist in the system anyway.
206*10946SSangeeta.Misra@Sun.COM 	 */
207*10946SSangeeta.Misra@Sun.COM 	(void) strlcpy(sn->sd_srvID, val, sizeof (sn->sd_srvID));
208*10946SSangeeta.Misra@Sun.COM 	return (ILBADM_OK);
209*10946SSangeeta.Misra@Sun.COM }
210*10946SSangeeta.Misra@Sun.COM 
211*10946SSangeeta.Misra@Sun.COM static struct in_addr
i_next_in_addr(struct in_addr * a,int dir)212*10946SSangeeta.Misra@Sun.COM i_next_in_addr(struct in_addr *a, int dir)
213*10946SSangeeta.Misra@Sun.COM {
214*10946SSangeeta.Misra@Sun.COM 	struct in_addr	new_in;
215*10946SSangeeta.Misra@Sun.COM 	uint32_t	iah;
216*10946SSangeeta.Misra@Sun.COM 
217*10946SSangeeta.Misra@Sun.COM 	iah = ntohl(a->s_addr);
218*10946SSangeeta.Misra@Sun.COM 	if (dir == 1)
219*10946SSangeeta.Misra@Sun.COM 		iah++;
220*10946SSangeeta.Misra@Sun.COM 	else
221*10946SSangeeta.Misra@Sun.COM 		iah--;
222*10946SSangeeta.Misra@Sun.COM 	new_in.s_addr = htonl(iah);
223*10946SSangeeta.Misra@Sun.COM 	return (new_in);
224*10946SSangeeta.Misra@Sun.COM }
225*10946SSangeeta.Misra@Sun.COM 
226*10946SSangeeta.Misra@Sun.COM static ilbadm_status_t
i_expand_ipv4range(ilbadm_sgroup_t * sg,ilb_server_data_t * srv,ilb_ip_addr_t * ip1,ilb_ip_addr_t * ip2)227*10946SSangeeta.Misra@Sun.COM i_expand_ipv4range(ilbadm_sgroup_t *sg, ilb_server_data_t *srv,
228*10946SSangeeta.Misra@Sun.COM     ilb_ip_addr_t *ip1, ilb_ip_addr_t *ip2)
229*10946SSangeeta.Misra@Sun.COM {
230*10946SSangeeta.Misra@Sun.COM 	struct in_addr	*a1;
231*10946SSangeeta.Misra@Sun.COM 	ilbadm_servnode_t	*sn_new;
232*10946SSangeeta.Misra@Sun.COM 	ilb_ip_addr_t	new_ip;
233*10946SSangeeta.Misra@Sun.COM 
234*10946SSangeeta.Misra@Sun.COM 	a1 = &ip1->ia_v4;
235*10946SSangeeta.Misra@Sun.COM 
236*10946SSangeeta.Misra@Sun.COM 	new_ip.ia_af = AF_INET;
237*10946SSangeeta.Misra@Sun.COM 	new_ip.ia_v4 = i_next_in_addr(a1, 1);
238*10946SSangeeta.Misra@Sun.COM 	while (ilb_cmp_ipaddr(&new_ip, ip2, NULL) < 1) {
239*10946SSangeeta.Misra@Sun.COM 		sn_new = i_new_sg_elem(sg);
240*10946SSangeeta.Misra@Sun.COM 		sn_new->s_spec.sd_addr = new_ip;
241*10946SSangeeta.Misra@Sun.COM 		sn_new->s_spec.sd_minport = srv->sd_minport;
242*10946SSangeeta.Misra@Sun.COM 		sn_new->s_spec.sd_maxport = srv->sd_maxport;
243*10946SSangeeta.Misra@Sun.COM 		new_ip.ia_v4 = i_next_in_addr(&new_ip.ia_v4, 1);
244*10946SSangeeta.Misra@Sun.COM 	}
245*10946SSangeeta.Misra@Sun.COM 	return (ILBADM_OK);
246*10946SSangeeta.Misra@Sun.COM }
247*10946SSangeeta.Misra@Sun.COM 
248*10946SSangeeta.Misra@Sun.COM static struct in6_addr
i_next_in6_addr(struct in6_addr * a,int dir)249*10946SSangeeta.Misra@Sun.COM i_next_in6_addr(struct in6_addr *a, int dir)
250*10946SSangeeta.Misra@Sun.COM {
251*10946SSangeeta.Misra@Sun.COM 	struct in6_addr	ia6;
252*10946SSangeeta.Misra@Sun.COM 	uint64_t	al, ah;
253*10946SSangeeta.Misra@Sun.COM 
254*10946SSangeeta.Misra@Sun.COM 	ah = INV6_N2H_MSB64(a);
255*10946SSangeeta.Misra@Sun.COM 	al = INV6_N2H_LSB64(a);
256*10946SSangeeta.Misra@Sun.COM 
257*10946SSangeeta.Misra@Sun.COM 	if (dir == 1) {
258*10946SSangeeta.Misra@Sun.COM 		/* overflow */
259*10946SSangeeta.Misra@Sun.COM 		if (++al == 0)
260*10946SSangeeta.Misra@Sun.COM 			ah++;
261*10946SSangeeta.Misra@Sun.COM 	} else {
262*10946SSangeeta.Misra@Sun.COM 		/* underflow */
263*10946SSangeeta.Misra@Sun.COM 		if (--al == 0xffffffff)
264*10946SSangeeta.Misra@Sun.COM 			ah--;
265*10946SSangeeta.Misra@Sun.COM 	}
266*10946SSangeeta.Misra@Sun.COM 
267*10946SSangeeta.Misra@Sun.COM 	INV6_H2N_MSB64(&ia6, ah);
268*10946SSangeeta.Misra@Sun.COM 	INV6_H2N_LSB64(&ia6, al);
269*10946SSangeeta.Misra@Sun.COM 	return (ia6);
270*10946SSangeeta.Misra@Sun.COM }
271*10946SSangeeta.Misra@Sun.COM 
272*10946SSangeeta.Misra@Sun.COM 
273*10946SSangeeta.Misra@Sun.COM static ilbadm_status_t
i_expand_ipv6range(ilbadm_sgroup_t * sg,ilb_server_data_t * srv,ilb_ip_addr_t * ip1,ilb_ip_addr_t * ip2)274*10946SSangeeta.Misra@Sun.COM i_expand_ipv6range(ilbadm_sgroup_t *sg, ilb_server_data_t *srv,
275*10946SSangeeta.Misra@Sun.COM     ilb_ip_addr_t *ip1, ilb_ip_addr_t *ip2)
276*10946SSangeeta.Misra@Sun.COM {
277*10946SSangeeta.Misra@Sun.COM 	struct in6_addr	*a1;
278*10946SSangeeta.Misra@Sun.COM 	ilbadm_servnode_t	*sn_new;
279*10946SSangeeta.Misra@Sun.COM 	ilb_ip_addr_t	new_ip;
280*10946SSangeeta.Misra@Sun.COM 
281*10946SSangeeta.Misra@Sun.COM 	a1 = &ip1->ia_v6;
282*10946SSangeeta.Misra@Sun.COM 
283*10946SSangeeta.Misra@Sun.COM 	new_ip.ia_af = AF_INET6;
284*10946SSangeeta.Misra@Sun.COM 	new_ip.ia_v6 = i_next_in6_addr(a1, 1);
285*10946SSangeeta.Misra@Sun.COM 	while (ilb_cmp_ipaddr(&new_ip, ip2, NULL) < 1) {
286*10946SSangeeta.Misra@Sun.COM 		sn_new = i_new_sg_elem(sg);
287*10946SSangeeta.Misra@Sun.COM 		sn_new->s_spec.sd_addr = new_ip;
288*10946SSangeeta.Misra@Sun.COM 		sn_new->s_spec.sd_minport = srv->sd_minport;
289*10946SSangeeta.Misra@Sun.COM 		sn_new->s_spec.sd_maxport = srv->sd_maxport;
290*10946SSangeeta.Misra@Sun.COM 		new_ip.ia_v6 = i_next_in6_addr(&new_ip.ia_v6, 1);
291*10946SSangeeta.Misra@Sun.COM 	}
292*10946SSangeeta.Misra@Sun.COM 	return (ILBADM_OK);
293*10946SSangeeta.Misra@Sun.COM }
294*10946SSangeeta.Misra@Sun.COM 
295*10946SSangeeta.Misra@Sun.COM 
296*10946SSangeeta.Misra@Sun.COM /*
297*10946SSangeeta.Misra@Sun.COM  * we create a list node in the servergroup for every ip address
298*10946SSangeeta.Misra@Sun.COM  * in the range [ip1, ip2], where we interpret the ip addresses as
299*10946SSangeeta.Misra@Sun.COM  * numbers
300*10946SSangeeta.Misra@Sun.COM  * the first ip address is already stored in "sn"
301*10946SSangeeta.Misra@Sun.COM  */
302*10946SSangeeta.Misra@Sun.COM static ilbadm_status_t
i_expand_iprange(ilbadm_sgroup_t * sg,ilb_server_data_t * sr,ilb_ip_addr_t * ip1,ilb_ip_addr_t * ip2)303*10946SSangeeta.Misra@Sun.COM i_expand_iprange(ilbadm_sgroup_t *sg, ilb_server_data_t *sr,
304*10946SSangeeta.Misra@Sun.COM     ilb_ip_addr_t *ip1, ilb_ip_addr_t *ip2)
305*10946SSangeeta.Misra@Sun.COM {
306*10946SSangeeta.Misra@Sun.COM 	int		cmp;
307*10946SSangeeta.Misra@Sun.COM 	int64_t		delta;
308*10946SSangeeta.Misra@Sun.COM 
309*10946SSangeeta.Misra@Sun.COM 	if (ip2->ia_af == 0)
310*10946SSangeeta.Misra@Sun.COM 		return (ILBADM_OK);
311*10946SSangeeta.Misra@Sun.COM 
312*10946SSangeeta.Misra@Sun.COM 	if (ip1->ia_af != ip2->ia_af) {
313*10946SSangeeta.Misra@Sun.COM 		ilbadm_err(gettext("IP address mismatch"));
314*10946SSangeeta.Misra@Sun.COM 		return (ILBADM_LIBERR);
315*10946SSangeeta.Misra@Sun.COM 	}
316*10946SSangeeta.Misra@Sun.COM 
317*10946SSangeeta.Misra@Sun.COM 	/* if ip addresses are the same, we're done */
318*10946SSangeeta.Misra@Sun.COM 	if ((cmp = ilb_cmp_ipaddr(ip1, ip2, &delta)) == 0)
319*10946SSangeeta.Misra@Sun.COM 		return (ILBADM_OK);
320*10946SSangeeta.Misra@Sun.COM 	if (cmp == 1) {
321*10946SSangeeta.Misra@Sun.COM 		ilbadm_err(gettext("starting IP address is must be less"
322*10946SSangeeta.Misra@Sun.COM 		    " than ending ip address in ip range specification"));
323*10946SSangeeta.Misra@Sun.COM 		return (ILBADM_LIBERR);
324*10946SSangeeta.Misra@Sun.COM 	}
325*10946SSangeeta.Misra@Sun.COM 
326*10946SSangeeta.Misra@Sun.COM 	/* if the implicit number of IPs is too large, stop */
327*10946SSangeeta.Misra@Sun.COM 	if (abs((int)delta) > MAX_IP_SPREAD)
328*10946SSangeeta.Misra@Sun.COM 		return (ILBADM_TOOMANYIPADDR);
329*10946SSangeeta.Misra@Sun.COM 
330*10946SSangeeta.Misra@Sun.COM 	switch (ip1->ia_af) {
331*10946SSangeeta.Misra@Sun.COM 	case AF_INET: return (i_expand_ipv4range(sg, sr, ip1, ip2));
332*10946SSangeeta.Misra@Sun.COM 		/* not reached */
333*10946SSangeeta.Misra@Sun.COM 		break;
334*10946SSangeeta.Misra@Sun.COM 	case AF_INET6: return (i_expand_ipv6range(sg, sr, ip1, ip2));
335*10946SSangeeta.Misra@Sun.COM 		/* not reached */
336*10946SSangeeta.Misra@Sun.COM 		break;
337*10946SSangeeta.Misra@Sun.COM 	}
338*10946SSangeeta.Misra@Sun.COM 	return (ILBADM_INVAL_AF);
339*10946SSangeeta.Misra@Sun.COM }
340*10946SSangeeta.Misra@Sun.COM 
341*10946SSangeeta.Misra@Sun.COM /*
342*10946SSangeeta.Misra@Sun.COM  * parse a port spec (number or by service name) and
343*10946SSangeeta.Misra@Sun.COM  * return the numeric port in *host* byte order
344*10946SSangeeta.Misra@Sun.COM  *
345*10946SSangeeta.Misra@Sun.COM  * Upon return, *flags contains ILB_FLAGS_SRV_PORTNAME if a service name matches
346*10946SSangeeta.Misra@Sun.COM  */
347*10946SSangeeta.Misra@Sun.COM static int
i_parseport(char * port,char * proto,int * flags)348*10946SSangeeta.Misra@Sun.COM i_parseport(char *port, char *proto, int *flags)
349*10946SSangeeta.Misra@Sun.COM {
350*10946SSangeeta.Misra@Sun.COM 	struct servent	*se;
351*10946SSangeeta.Misra@Sun.COM 
352*10946SSangeeta.Misra@Sun.COM 	/* assumption: port names start with a non-digit */
353*10946SSangeeta.Misra@Sun.COM 	if (isdigit(port[0])) {
354*10946SSangeeta.Misra@Sun.COM 		if (flags != NULL)
355*10946SSangeeta.Misra@Sun.COM 			*flags &= ~ILB_FLAGS_SRV_PORTNAME;
356*10946SSangeeta.Misra@Sun.COM 		return ((int)strtol(port, NULL, 10));
357*10946SSangeeta.Misra@Sun.COM 	}
358*10946SSangeeta.Misra@Sun.COM 
359*10946SSangeeta.Misra@Sun.COM 	se = getservbyname(port, proto);
360*10946SSangeeta.Misra@Sun.COM 	if (se == NULL)
361*10946SSangeeta.Misra@Sun.COM 		return (-1);
362*10946SSangeeta.Misra@Sun.COM 
363*10946SSangeeta.Misra@Sun.COM 	if (flags != NULL)
364*10946SSangeeta.Misra@Sun.COM 		*flags |= ILB_FLAGS_SRV_PORTNAME;
365*10946SSangeeta.Misra@Sun.COM 
366*10946SSangeeta.Misra@Sun.COM 	/*
367*10946SSangeeta.Misra@Sun.COM 	 * we need to convert to host byte order to be in sync with
368*10946SSangeeta.Misra@Sun.COM 	 * numerical ports. since result needs to be compared, this
369*10946SSangeeta.Misra@Sun.COM 	 * is preferred to returning NW byte order
370*10946SSangeeta.Misra@Sun.COM 	 */
371*10946SSangeeta.Misra@Sun.COM 	return ((int)(ntohs(se->s_port)));
372*10946SSangeeta.Misra@Sun.COM }
373*10946SSangeeta.Misra@Sun.COM 
374*10946SSangeeta.Misra@Sun.COM /*
375*10946SSangeeta.Misra@Sun.COM  * matches one hostname or IP address and stores it in "store".
376*10946SSangeeta.Misra@Sun.COM  * space must have been pre-allocated to accept data
377*10946SSangeeta.Misra@Sun.COM  * "sg" != NULL only for cases where ip ranges may be coming in.
378*10946SSangeeta.Misra@Sun.COM  */
379*10946SSangeeta.Misra@Sun.COM static ilbadm_status_t
i_match_hostorip(void * store,ilbadm_sgroup_t * sg,char * val,int flags,ilbadm_key_code_t keyword)380*10946SSangeeta.Misra@Sun.COM i_match_hostorip(void *store, ilbadm_sgroup_t *sg, char *val,
381*10946SSangeeta.Misra@Sun.COM     int flags, ilbadm_key_code_t keyword)
382*10946SSangeeta.Misra@Sun.COM {
383*10946SSangeeta.Misra@Sun.COM 	boolean_t	is_ip_range_ok = flags & OPT_IP_RANGE;
384*10946SSangeeta.Misra@Sun.COM 	boolean_t	is_addr_numeric = flags & OPT_NUMERIC_ONLY;
385*10946SSangeeta.Misra@Sun.COM 	boolean_t	is_ports_ok = flags & OPT_PORTS;
386*10946SSangeeta.Misra@Sun.COM 	boolean_t	ports_only = flags & OPT_PORTS_ONLY;
387*10946SSangeeta.Misra@Sun.COM 	boolean_t	is_nat_src = flags & OPT_NAT;
388*10946SSangeeta.Misra@Sun.COM 	char		*port_pref, *dash;
389*10946SSangeeta.Misra@Sun.COM 	char		*port1p, *port2p, *host2p, *host1p;
390*10946SSangeeta.Misra@Sun.COM 	char		*close1, *close2;
391*10946SSangeeta.Misra@Sun.COM 	ilb_ip_addr_t	ip2store;
392*10946SSangeeta.Misra@Sun.COM 	ilb_ip_addr_t	*ip1, *ip2;
393*10946SSangeeta.Misra@Sun.COM 	int		p1, p2;
394*10946SSangeeta.Misra@Sun.COM 	ilb_server_data_t	*s = NULL;
395*10946SSangeeta.Misra@Sun.COM 	ilbadm_status_t	rc = ILBADM_OK;
396*10946SSangeeta.Misra@Sun.COM 	int		af = AF_INET;
397*10946SSangeeta.Misra@Sun.COM 	addr_type_t	at = 0;
398*10946SSangeeta.Misra@Sun.COM 	int		p_flg;
399*10946SSangeeta.Misra@Sun.COM 	struct in6_addr v6nameaddr;
400*10946SSangeeta.Misra@Sun.COM 
401*10946SSangeeta.Misra@Sun.COM 	port1p = port2p = host2p = host1p =  NULL;
402*10946SSangeeta.Misra@Sun.COM 	port_pref = dash = NULL;
403*10946SSangeeta.Misra@Sun.COM 	close1 = close2 = NULL;
404*10946SSangeeta.Misra@Sun.COM 	errno = 0;
405*10946SSangeeta.Misra@Sun.COM 
406*10946SSangeeta.Misra@Sun.COM 	if (is_nat_src) {
407*10946SSangeeta.Misra@Sun.COM 		ilb_rule_data_t *rd = (ilb_rule_data_t *)store;
408*10946SSangeeta.Misra@Sun.COM 
409*10946SSangeeta.Misra@Sun.COM 		ip1 = &rd->r_nat_src_start;
410*10946SSangeeta.Misra@Sun.COM 		ip2 = &rd->r_nat_src_end;
411*10946SSangeeta.Misra@Sun.COM 	} else {
412*10946SSangeeta.Misra@Sun.COM 		ilbadm_servnode_t *sn = (ilbadm_servnode_t *)store;
413*10946SSangeeta.Misra@Sun.COM 
414*10946SSangeeta.Misra@Sun.COM 		s = &sn->s_spec;
415*10946SSangeeta.Misra@Sun.COM 		ip1 = &s->sd_addr;
416*10946SSangeeta.Misra@Sun.COM 		ip2 = &ip2store;
417*10946SSangeeta.Misra@Sun.COM 		bzero(ip2, sizeof (*ip2));
418*10946SSangeeta.Misra@Sun.COM 	}
419*10946SSangeeta.Misra@Sun.COM 
420*10946SSangeeta.Misra@Sun.COM 	if (ports_only) {
421*10946SSangeeta.Misra@Sun.COM 		is_ports_ok = B_TRUE;
422*10946SSangeeta.Misra@Sun.COM 		port_pref = val - 1; /* we increment again later on */
423*10946SSangeeta.Misra@Sun.COM 		goto ports;
424*10946SSangeeta.Misra@Sun.COM 	}
425*10946SSangeeta.Misra@Sun.COM 
426*10946SSangeeta.Misra@Sun.COM 	/*
427*10946SSangeeta.Misra@Sun.COM 	 * we parse the syntax ip[-ip][:port[-port]]
428*10946SSangeeta.Misra@Sun.COM 	 * since IPv6 addresses contain ':'s as well, they need to be
429*10946SSangeeta.Misra@Sun.COM 	 * enclosed in "[]" to be distinct from a potential port spec.
430*10946SSangeeta.Misra@Sun.COM 	 * therefore, we need to first check whether we're dealing with
431*10946SSangeeta.Misra@Sun.COM 	 * IPv6 addresses before we can go search for the port seperator
432*10946SSangeeta.Misra@Sun.COM 	 * and ipv6 range could look like this: [ff::0]-[ff::255]:80
433*10946SSangeeta.Misra@Sun.COM 	 */
434*10946SSangeeta.Misra@Sun.COM 	if ((keyword == ILB_KEY_SERVER) && (strchr(val, ':') != NULL) &&
435*10946SSangeeta.Misra@Sun.COM 	    (*val != '[') && ((inet_pton(AF_INET6, val, &v6nameaddr)) != 0)) {
436*10946SSangeeta.Misra@Sun.COM 			/*
437*10946SSangeeta.Misra@Sun.COM 			 * V6 addresses must be enclosed within
438*10946SSangeeta.Misra@Sun.COM 			 * brackets when specifying server addresses
439*10946SSangeeta.Misra@Sun.COM 			 */
440*10946SSangeeta.Misra@Sun.COM 			rc = ILBADM_INVAL_SYNTAX;
441*10946SSangeeta.Misra@Sun.COM 			goto err_out;
442*10946SSangeeta.Misra@Sun.COM 	}
443*10946SSangeeta.Misra@Sun.COM 
444*10946SSangeeta.Misra@Sun.COM 	if (*val == '[') {
445*10946SSangeeta.Misra@Sun.COM 		af = AF_INET6;
446*10946SSangeeta.Misra@Sun.COM 
447*10946SSangeeta.Misra@Sun.COM 		val++;
448*10946SSangeeta.Misra@Sun.COM 		host1p = val;
449*10946SSangeeta.Misra@Sun.COM 
450*10946SSangeeta.Misra@Sun.COM 		close1 = strchr(val, (int)']');
451*10946SSangeeta.Misra@Sun.COM 		if (close1 == NULL) {
452*10946SSangeeta.Misra@Sun.COM 			rc = ILBADM_INVAL_SYNTAX;
453*10946SSangeeta.Misra@Sun.COM 			goto err_out;
454*10946SSangeeta.Misra@Sun.COM 		}
455*10946SSangeeta.Misra@Sun.COM 		*close1 = '\0';
456*10946SSangeeta.Misra@Sun.COM 		at = 0;
457*10946SSangeeta.Misra@Sun.COM 		rc = i_match_onehost(host1p, ip1, &at);
458*10946SSangeeta.Misra@Sun.COM 		if (rc != ILBADM_OK)
459*10946SSangeeta.Misra@Sun.COM 			goto err_out;
460*10946SSangeeta.Misra@Sun.COM 		if (at != numeric) {
461*10946SSangeeta.Misra@Sun.COM 			rc = ILBADM_INVAL_ADDR;
462*10946SSangeeta.Misra@Sun.COM 			goto err_out;
463*10946SSangeeta.Misra@Sun.COM 		}
464*10946SSangeeta.Misra@Sun.COM 		if (ip1->ia_af != af) {
465*10946SSangeeta.Misra@Sun.COM 			rc = ILBADM_INVAL_AF;
466*10946SSangeeta.Misra@Sun.COM 			goto err_out;
467*10946SSangeeta.Misra@Sun.COM 		}
468*10946SSangeeta.Misra@Sun.COM 		val = close1 + 1;
469*10946SSangeeta.Misra@Sun.COM 
470*10946SSangeeta.Misra@Sun.COM 		if (*val == PORT_SEP) {
471*10946SSangeeta.Misra@Sun.COM 			port_pref = val;
472*10946SSangeeta.Misra@Sun.COM 			goto ports;
473*10946SSangeeta.Misra@Sun.COM 		}
474*10946SSangeeta.Misra@Sun.COM 		if (*val == '-') {
475*10946SSangeeta.Misra@Sun.COM 			dash = val;
476*10946SSangeeta.Misra@Sun.COM 			if (!is_ip_range_ok) {
477*10946SSangeeta.Misra@Sun.COM 				ilbadm_err(gettext("port ranges not allowed"));
478*10946SSangeeta.Misra@Sun.COM 				rc = ILBADM_LIBERR;
479*10946SSangeeta.Misra@Sun.COM 				goto err_out;
480*10946SSangeeta.Misra@Sun.COM 			}
481*10946SSangeeta.Misra@Sun.COM 			val++;
482*10946SSangeeta.Misra@Sun.COM 			if (*val != '[') {
483*10946SSangeeta.Misra@Sun.COM 				rc = ILBADM_INVAL_SYNTAX;
484*10946SSangeeta.Misra@Sun.COM 				goto err_out;
485*10946SSangeeta.Misra@Sun.COM 			}
486*10946SSangeeta.Misra@Sun.COM 			val++;
487*10946SSangeeta.Misra@Sun.COM 			close2 = strchr(val, (int)']');
488*10946SSangeeta.Misra@Sun.COM 			if (close2 == NULL) {
489*10946SSangeeta.Misra@Sun.COM 				rc = ILBADM_INVAL_SYNTAX;
490*10946SSangeeta.Misra@Sun.COM 				goto err_out;
491*10946SSangeeta.Misra@Sun.COM 			}
492*10946SSangeeta.Misra@Sun.COM 			*close2 = '\0';
493*10946SSangeeta.Misra@Sun.COM 			host2p = val;
494*10946SSangeeta.Misra@Sun.COM 			at = 0;
495*10946SSangeeta.Misra@Sun.COM 			rc = i_match_onehost(host2p, ip2, &at);
496*10946SSangeeta.Misra@Sun.COM 			if (rc != ILBADM_OK)
497*10946SSangeeta.Misra@Sun.COM 				goto err_out;
498*10946SSangeeta.Misra@Sun.COM 			if (at != numeric) {
499*10946SSangeeta.Misra@Sun.COM 				rc = ILBADM_INVAL_ADDR;
500*10946SSangeeta.Misra@Sun.COM 				goto err_out;
501*10946SSangeeta.Misra@Sun.COM 			}
502*10946SSangeeta.Misra@Sun.COM 			if (ip2->ia_af != af) {
503*10946SSangeeta.Misra@Sun.COM 				rc = ILBADM_INVAL_AF;
504*10946SSangeeta.Misra@Sun.COM 				goto err_out;
505*10946SSangeeta.Misra@Sun.COM 			}
506*10946SSangeeta.Misra@Sun.COM 			val = close2+1;
507*10946SSangeeta.Misra@Sun.COM 		}
508*10946SSangeeta.Misra@Sun.COM 	}
509*10946SSangeeta.Misra@Sun.COM 
510*10946SSangeeta.Misra@Sun.COM 	/* ports always potentially allow ranges - XXXms: check? */
511*10946SSangeeta.Misra@Sun.COM 	port_pref = strchr(val, (int)PORT_SEP);
512*10946SSangeeta.Misra@Sun.COM ports:
513*10946SSangeeta.Misra@Sun.COM 	if (port_pref != NULL && is_ports_ok) {
514*10946SSangeeta.Misra@Sun.COM 		port1p = port_pref + 1;
515*10946SSangeeta.Misra@Sun.COM 		*port_pref = '\0';
516*10946SSangeeta.Misra@Sun.COM 
517*10946SSangeeta.Misra@Sun.COM 		dash = strchr(port1p, (int)'-');
518*10946SSangeeta.Misra@Sun.COM 		if (dash != NULL) {
519*10946SSangeeta.Misra@Sun.COM 			port2p = dash + 1;
520*10946SSangeeta.Misra@Sun.COM 			*dash = '\0';
521*10946SSangeeta.Misra@Sun.COM 		}
522*10946SSangeeta.Misra@Sun.COM 		if (port1p != NULL) {
523*10946SSangeeta.Misra@Sun.COM 			p1 = i_parseport(port1p, NULL, &p_flg);
524*10946SSangeeta.Misra@Sun.COM 			if (p1 == -1 || p1 == 0 || p1 > ILB_MAX_PORT) {
525*10946SSangeeta.Misra@Sun.COM 				ilbadm_err(gettext("invalid port value %s"
526*10946SSangeeta.Misra@Sun.COM 				    " specified"), port1p);
527*10946SSangeeta.Misra@Sun.COM 				rc = ILBADM_LIBERR;
528*10946SSangeeta.Misra@Sun.COM 				goto err_out;
529*10946SSangeeta.Misra@Sun.COM 			}
530*10946SSangeeta.Misra@Sun.COM 			s->sd_minport = htons((in_port_t)p1);
531*10946SSangeeta.Misra@Sun.COM 			if (p_flg & ILB_FLAGS_SRV_PORTNAME)
532*10946SSangeeta.Misra@Sun.COM 				s->sd_flags |= ILB_FLAGS_SRV_PORTNAME;
533*10946SSangeeta.Misra@Sun.COM 		}
534*10946SSangeeta.Misra@Sun.COM 		if (port2p != NULL) {
535*10946SSangeeta.Misra@Sun.COM 			/* ranges are only allowed for numeric ports */
536*10946SSangeeta.Misra@Sun.COM 			if (p_flg & ILB_FLAGS_SRV_PORTNAME) {
537*10946SSangeeta.Misra@Sun.COM 				ilbadm_err(gettext("ranges are only allowed"
538*10946SSangeeta.Misra@Sun.COM 				    " for numeric ports"));
539*10946SSangeeta.Misra@Sun.COM 				rc = ILBADM_LIBERR;
540*10946SSangeeta.Misra@Sun.COM 				goto err_out;
541*10946SSangeeta.Misra@Sun.COM 			}
542*10946SSangeeta.Misra@Sun.COM 			p2 = i_parseport(port2p, NULL, &p_flg);
543*10946SSangeeta.Misra@Sun.COM 			if (p2 == -1 || p2 <= p1 || p2 > ILB_MAX_PORT ||
544*10946SSangeeta.Misra@Sun.COM 			    (p_flg & ILB_FLAGS_SRV_PORTNAME) ==
545*10946SSangeeta.Misra@Sun.COM 			    ILB_FLAGS_SRV_PORTNAME) {
546*10946SSangeeta.Misra@Sun.COM 				ilbadm_err(gettext("invalid port value %s"
547*10946SSangeeta.Misra@Sun.COM 				    " specified"), port2p);
548*10946SSangeeta.Misra@Sun.COM 				rc = ILBADM_LIBERR;
549*10946SSangeeta.Misra@Sun.COM 				goto err_out;
550*10946SSangeeta.Misra@Sun.COM 			}
551*10946SSangeeta.Misra@Sun.COM 			s->sd_maxport = htons((in_port_t)p2);
552*10946SSangeeta.Misra@Sun.COM 		}
553*10946SSangeeta.Misra@Sun.COM 		/*
554*10946SSangeeta.Misra@Sun.COM 		 * we fill the '-' back in, but not the port seperator,
555*10946SSangeeta.Misra@Sun.COM 		 * as the \0 in its place terminates the ip address(es)
556*10946SSangeeta.Misra@Sun.COM 		 */
557*10946SSangeeta.Misra@Sun.COM 		if (dash != NULL)
558*10946SSangeeta.Misra@Sun.COM 			*dash = '-';
559*10946SSangeeta.Misra@Sun.COM 		if (ports_only)
560*10946SSangeeta.Misra@Sun.COM 			goto out;
561*10946SSangeeta.Misra@Sun.COM 	}
562*10946SSangeeta.Misra@Sun.COM 
563*10946SSangeeta.Misra@Sun.COM 	if (af == AF_INET6)
564*10946SSangeeta.Misra@Sun.COM 		goto out;
565*10946SSangeeta.Misra@Sun.COM 
566*10946SSangeeta.Misra@Sun.COM 	/*
567*10946SSangeeta.Misra@Sun.COM 	 * we need to handle these situations for hosts:
568*10946SSangeeta.Misra@Sun.COM 	 *   a. ip address
569*10946SSangeeta.Misra@Sun.COM 	 *   b. ip address range (ip1-ip2)
570*10946SSangeeta.Misra@Sun.COM 	 *   c. a hostname (may include '-' or start with a digit)
571*10946SSangeeta.Misra@Sun.COM 	 *
572*10946SSangeeta.Misra@Sun.COM 	 * We want to do hostname lookup only if we're quite sure that
573*10946SSangeeta.Misra@Sun.COM 	 * we actually are looking at neither a single IP address nor a
574*10946SSangeeta.Misra@Sun.COM 	 * range of same, as this can hang if name service is not set up
575*10946SSangeeta.Misra@Sun.COM 	 * (sth. likely in a LB environment).
576*10946SSangeeta.Misra@Sun.COM 	 *
577*10946SSangeeta.Misra@Sun.COM 	 * here's how we proceed:
578*10946SSangeeta.Misra@Sun.COM 	 * 1. try to match numeric only. If that succeeds, we're done.
579*10946SSangeeta.Misra@Sun.COM 	 *    (getaddrinfo, which we call in i_match_onehost(), fails if
580*10946SSangeeta.Misra@Sun.COM 	 *    it encounters a '-')
581*10946SSangeeta.Misra@Sun.COM 	 * 2. search for a '-'; if we find one, try numeric match for
582*10946SSangeeta.Misra@Sun.COM 	 *    both sides. if this fails:
583*10946SSangeeta.Misra@Sun.COM 	 * 3. re-insert '-' and try for a legal hostname.
584*10946SSangeeta.Misra@Sun.COM 	 */
585*10946SSangeeta.Misra@Sun.COM 	/* 1. */
586*10946SSangeeta.Misra@Sun.COM 	at = numeric;
587*10946SSangeeta.Misra@Sun.COM 	rc = i_match_onehost(val, ip1, &at);
588*10946SSangeeta.Misra@Sun.COM 	if (rc == ILBADM_OK)
589*10946SSangeeta.Misra@Sun.COM 		goto out;
590*10946SSangeeta.Misra@Sun.COM 
591*10946SSangeeta.Misra@Sun.COM 	/* 2. */
592*10946SSangeeta.Misra@Sun.COM 	dash = strchr(val, (int)'-');
593*10946SSangeeta.Misra@Sun.COM 	if (dash != NULL && is_ip_range_ok) {
594*10946SSangeeta.Misra@Sun.COM 		host2p = dash + 1;
595*10946SSangeeta.Misra@Sun.COM 		*dash = '\0';
596*10946SSangeeta.Misra@Sun.COM 		at = numeric;
597*10946SSangeeta.Misra@Sun.COM 		rc = i_match_onehost(host2p, ip2, &at);
598*10946SSangeeta.Misra@Sun.COM 		if (rc != ILBADM_OK || at != numeric) {
599*10946SSangeeta.Misra@Sun.COM 			*dash = '-';
600*10946SSangeeta.Misra@Sun.COM 			dash = NULL;
601*10946SSangeeta.Misra@Sun.COM 			bzero(ip2, sizeof (*ip2));
602*10946SSangeeta.Misra@Sun.COM 			goto hostname;
603*10946SSangeeta.Misra@Sun.COM 		}
604*10946SSangeeta.Misra@Sun.COM 		/*
605*10946SSangeeta.Misra@Sun.COM 		 * if the RHS of '-' is an IP but LHS is not, we might
606*10946SSangeeta.Misra@Sun.COM 		 * have a hostname of form x-y where y is just a number
607*10946SSangeeta.Misra@Sun.COM 		 * (this seems a valid IPv4 address), so we need to
608*10946SSangeeta.Misra@Sun.COM 		 * try a complete hostname
609*10946SSangeeta.Misra@Sun.COM 		 */
610*10946SSangeeta.Misra@Sun.COM 		rc = i_match_onehost(val, ip1, &at);
611*10946SSangeeta.Misra@Sun.COM 		if (rc != ILBADM_OK || at != numeric) {
612*10946SSangeeta.Misra@Sun.COM 			*dash = '-';
613*10946SSangeeta.Misra@Sun.COM 			dash = NULL;
614*10946SSangeeta.Misra@Sun.COM 			goto hostname;
615*10946SSangeeta.Misra@Sun.COM 		}
616*10946SSangeeta.Misra@Sun.COM 		goto out;
617*10946SSangeeta.Misra@Sun.COM 	}
618*10946SSangeeta.Misra@Sun.COM hostname:
619*10946SSangeeta.Misra@Sun.COM 	/* 3. */
620*10946SSangeeta.Misra@Sun.COM 
621*10946SSangeeta.Misra@Sun.COM 	if (is_addr_numeric)
622*10946SSangeeta.Misra@Sun.COM 		at = numeric;
623*10946SSangeeta.Misra@Sun.COM 	else
624*10946SSangeeta.Misra@Sun.COM 		at = 0;
625*10946SSangeeta.Misra@Sun.COM 	rc = i_match_onehost(val, ip1, &at);
626*10946SSangeeta.Misra@Sun.COM 	if (rc != ILBADM_OK) {
627*10946SSangeeta.Misra@Sun.COM 		goto out;
628*10946SSangeeta.Misra@Sun.COM 	}
629*10946SSangeeta.Misra@Sun.COM 	if (s != NULL) {
630*10946SSangeeta.Misra@Sun.COM 		s->sd_flags |= ILB_FLAGS_SRV_HOSTNAME;
631*10946SSangeeta.Misra@Sun.COM 		/* XXX: todo: save hostname for re-display for admin */
632*10946SSangeeta.Misra@Sun.COM 	}
633*10946SSangeeta.Misra@Sun.COM 
634*10946SSangeeta.Misra@Sun.COM out:
635*10946SSangeeta.Misra@Sun.COM 	if (dash != NULL && !is_nat_src) {
636*10946SSangeeta.Misra@Sun.COM 		rc = i_expand_iprange(sg, s, ip1, ip2);
637*10946SSangeeta.Misra@Sun.COM 		if (rc != ILBADM_OK)
638*10946SSangeeta.Misra@Sun.COM 			goto err_out;
639*10946SSangeeta.Misra@Sun.COM 	}
640*10946SSangeeta.Misra@Sun.COM 
641*10946SSangeeta.Misra@Sun.COM 	if (is_nat_src && host2p == NULL)
642*10946SSangeeta.Misra@Sun.COM 		*ip2 = *ip1;
643*10946SSangeeta.Misra@Sun.COM 
644*10946SSangeeta.Misra@Sun.COM err_out:
645*10946SSangeeta.Misra@Sun.COM 	/*
646*10946SSangeeta.Misra@Sun.COM 	 * we re-insert what we overwrote, especially in the error case
647*10946SSangeeta.Misra@Sun.COM 	 */
648*10946SSangeeta.Misra@Sun.COM 	if (close2 != NULL)
649*10946SSangeeta.Misra@Sun.COM 		*close2 = ']';
650*10946SSangeeta.Misra@Sun.COM 	if (close1 != NULL)
651*10946SSangeeta.Misra@Sun.COM 		*close1 = '[';
652*10946SSangeeta.Misra@Sun.COM 	if (dash != NULL)
653*10946SSangeeta.Misra@Sun.COM 		*dash = '-';
654*10946SSangeeta.Misra@Sun.COM 	if (port_pref != NULL && !ports_only)
655*10946SSangeeta.Misra@Sun.COM 		*port_pref = PORT_SEP;
656*10946SSangeeta.Misra@Sun.COM 
657*10946SSangeeta.Misra@Sun.COM 	return (rc);
658*10946SSangeeta.Misra@Sun.COM }
659*10946SSangeeta.Misra@Sun.COM 
660*10946SSangeeta.Misra@Sun.COM /*
661*10946SSangeeta.Misra@Sun.COM  * type-agnostic helper function to return a pointer to a
662*10946SSangeeta.Misra@Sun.COM  * pristine (and maybe freshly allocated) piece of storage
663*10946SSangeeta.Misra@Sun.COM  * ready for something fitting "key"
664*10946SSangeeta.Misra@Sun.COM  */
665*10946SSangeeta.Misra@Sun.COM static void *
i_new_storep(void * store,ilbadm_key_code_t key)666*10946SSangeeta.Misra@Sun.COM i_new_storep(void *store, ilbadm_key_code_t key)
667*10946SSangeeta.Misra@Sun.COM {
668*10946SSangeeta.Misra@Sun.COM 	void	*res;
669*10946SSangeeta.Misra@Sun.COM 
670*10946SSangeeta.Misra@Sun.COM 	switch (key) {
671*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_SERVER:
672*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_SERVRANGE:
673*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_SERVERID:
674*10946SSangeeta.Misra@Sun.COM 		res = (void *) i_new_sg_elem(store);
675*10946SSangeeta.Misra@Sun.COM 		break;
676*10946SSangeeta.Misra@Sun.COM 	default: res = NULL;
677*10946SSangeeta.Misra@Sun.COM 		break;
678*10946SSangeeta.Misra@Sun.COM 	}
679*10946SSangeeta.Misra@Sun.COM 
680*10946SSangeeta.Misra@Sun.COM 	return (res);
681*10946SSangeeta.Misra@Sun.COM }
682*10946SSangeeta.Misra@Sun.COM 
683*10946SSangeeta.Misra@Sun.COM /*
684*10946SSangeeta.Misra@Sun.COM  * make sure everything that needs to be there is there
685*10946SSangeeta.Misra@Sun.COM  */
686*10946SSangeeta.Misra@Sun.COM ilbadm_status_t
i_check_rule_spec(ilb_rule_data_t * rd)687*10946SSangeeta.Misra@Sun.COM i_check_rule_spec(ilb_rule_data_t *rd)
688*10946SSangeeta.Misra@Sun.COM {
689*10946SSangeeta.Misra@Sun.COM 	int32_t		vip_af = rd->r_vip.ia_af;
690*10946SSangeeta.Misra@Sun.COM 	ilb_ip_addr_t	*prxy_src;
691*10946SSangeeta.Misra@Sun.COM 
692*10946SSangeeta.Misra@Sun.COM 	if (vip_af != AF_INET && vip_af != AF_INET6)
693*10946SSangeeta.Misra@Sun.COM 		return (ILBADM_INVAL_AF);
694*10946SSangeeta.Misra@Sun.COM 
695*10946SSangeeta.Misra@Sun.COM 	if (*rd->r_sgname == '\0')
696*10946SSangeeta.Misra@Sun.COM 		return (ILBADM_ENOSGNAME);
697*10946SSangeeta.Misra@Sun.COM 
698*10946SSangeeta.Misra@Sun.COM 	if (rd->r_algo == 0 || rd->r_topo == 0) {
699*10946SSangeeta.Misra@Sun.COM 		ilbadm_err(gettext("lbalg or type is unspecified"));
700*10946SSangeeta.Misra@Sun.COM 		return (ILBADM_LIBERR);
701*10946SSangeeta.Misra@Sun.COM 	}
702*10946SSangeeta.Misra@Sun.COM 
703*10946SSangeeta.Misra@Sun.COM 	if (rd->r_topo == ILB_TOPO_NAT) {
704*10946SSangeeta.Misra@Sun.COM 		prxy_src = &rd->r_nat_src_start;
705*10946SSangeeta.Misra@Sun.COM 		if (prxy_src->ia_af != vip_af) {
706*10946SSangeeta.Misra@Sun.COM 			ilbadm_err(gettext("proxy-src is either missing"
707*10946SSangeeta.Misra@Sun.COM 			    " or its address family does not"
708*10946SSangeeta.Misra@Sun.COM 			    " match that of the VIP address"));
709*10946SSangeeta.Misra@Sun.COM 			return (ILBADM_LIBERR);
710*10946SSangeeta.Misra@Sun.COM 		}
711*10946SSangeeta.Misra@Sun.COM 	}
712*10946SSangeeta.Misra@Sun.COM 	/* extend as necessary */
713*10946SSangeeta.Misra@Sun.COM 
714*10946SSangeeta.Misra@Sun.COM 	return (ILBADM_OK);
715*10946SSangeeta.Misra@Sun.COM }
716*10946SSangeeta.Misra@Sun.COM 
717*10946SSangeeta.Misra@Sun.COM /*
718*10946SSangeeta.Misra@Sun.COM  * in parameter "sz" describes size (in bytes) of mask
719*10946SSangeeta.Misra@Sun.COM  */
720*10946SSangeeta.Misra@Sun.COM static int
mask_to_prefixlen(const uchar_t * mask,const int sz)721*10946SSangeeta.Misra@Sun.COM mask_to_prefixlen(const uchar_t *mask, const int sz)
722*10946SSangeeta.Misra@Sun.COM {
723*10946SSangeeta.Misra@Sun.COM 	uchar_t	c;
724*10946SSangeeta.Misra@Sun.COM 	int	i, j;
725*10946SSangeeta.Misra@Sun.COM 	int	len = 0;
726*10946SSangeeta.Misra@Sun.COM 	int	tmask;
727*10946SSangeeta.Misra@Sun.COM 
728*10946SSangeeta.Misra@Sun.COM 	/*
729*10946SSangeeta.Misra@Sun.COM 	 * for every byte in the mask, we start with most significant
730*10946SSangeeta.Misra@Sun.COM 	 * bit and work our way down to the least significant bit; as
731*10946SSangeeta.Misra@Sun.COM 	 * long as we find the bit set, we add 1 to the length. the
732*10946SSangeeta.Misra@Sun.COM 	 * first unset bit we encounter terminates this process
733*10946SSangeeta.Misra@Sun.COM 	 */
734*10946SSangeeta.Misra@Sun.COM 	for (i = 0; i < sz; i++) {
735*10946SSangeeta.Misra@Sun.COM 		c = mask[i];
736*10946SSangeeta.Misra@Sun.COM 		tmask = 1 << 7;
737*10946SSangeeta.Misra@Sun.COM 		for (j = 7; j >= 0; j--) {
738*10946SSangeeta.Misra@Sun.COM 			if ((c & tmask) == 0)
739*10946SSangeeta.Misra@Sun.COM 				return (len);
740*10946SSangeeta.Misra@Sun.COM 			len++;
741*10946SSangeeta.Misra@Sun.COM 			tmask >>= 1;
742*10946SSangeeta.Misra@Sun.COM 		}
743*10946SSangeeta.Misra@Sun.COM 	}
744*10946SSangeeta.Misra@Sun.COM 	return (len);
745*10946SSangeeta.Misra@Sun.COM }
746*10946SSangeeta.Misra@Sun.COM 
747*10946SSangeeta.Misra@Sun.COM int
ilbadm_mask_to_prefixlen(ilb_ip_addr_t * ip)748*10946SSangeeta.Misra@Sun.COM ilbadm_mask_to_prefixlen(ilb_ip_addr_t *ip)
749*10946SSangeeta.Misra@Sun.COM {
750*10946SSangeeta.Misra@Sun.COM 	int af = ip->ia_af;
751*10946SSangeeta.Misra@Sun.COM 	int len = 0;
752*10946SSangeeta.Misra@Sun.COM 
753*10946SSangeeta.Misra@Sun.COM 	assert(af == AF_INET || af == AF_INET6);
754*10946SSangeeta.Misra@Sun.COM 	switch (af) {
755*10946SSangeeta.Misra@Sun.COM 	case AF_INET:
756*10946SSangeeta.Misra@Sun.COM 		len = mask_to_prefixlen((uchar_t *)&ip->ia_v4.s_addr,
757*10946SSangeeta.Misra@Sun.COM 		    sizeof (ip->ia_v4));
758*10946SSangeeta.Misra@Sun.COM 		break;
759*10946SSangeeta.Misra@Sun.COM 	case AF_INET6:
760*10946SSangeeta.Misra@Sun.COM 		len = mask_to_prefixlen((uchar_t *)&ip->ia_v6.s6_addr,
761*10946SSangeeta.Misra@Sun.COM 		    sizeof (ip->ia_v6));
762*10946SSangeeta.Misra@Sun.COM 		break;
763*10946SSangeeta.Misra@Sun.COM 	}
764*10946SSangeeta.Misra@Sun.COM 	return (len);
765*10946SSangeeta.Misra@Sun.COM }
766*10946SSangeeta.Misra@Sun.COM 
767*10946SSangeeta.Misra@Sun.COM /* copied from ifconfig.c, changed to return symbolic constants */
768*10946SSangeeta.Misra@Sun.COM /*
769*10946SSangeeta.Misra@Sun.COM  * Convert a prefix length to a mask.
770*10946SSangeeta.Misra@Sun.COM  * Returns 1 if ok. 0 otherwise.
771*10946SSangeeta.Misra@Sun.COM  * Assumes the mask array is zero'ed by the caller.
772*10946SSangeeta.Misra@Sun.COM  */
773*10946SSangeeta.Misra@Sun.COM static boolean_t
in_prefixlentomask(int prefixlen,int maxlen,uchar_t * mask)774*10946SSangeeta.Misra@Sun.COM in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask)
775*10946SSangeeta.Misra@Sun.COM {
776*10946SSangeeta.Misra@Sun.COM 	if (prefixlen < 0 || prefixlen > maxlen)
777*10946SSangeeta.Misra@Sun.COM 		return (B_FALSE);
778*10946SSangeeta.Misra@Sun.COM 
779*10946SSangeeta.Misra@Sun.COM 	while (prefixlen > 0) {
780*10946SSangeeta.Misra@Sun.COM 		if (prefixlen >= 8) {
781*10946SSangeeta.Misra@Sun.COM 			*mask++ = 0xFF;
782*10946SSangeeta.Misra@Sun.COM 			prefixlen -= 8;
783*10946SSangeeta.Misra@Sun.COM 			continue;
784*10946SSangeeta.Misra@Sun.COM 		}
785*10946SSangeeta.Misra@Sun.COM 		*mask |= 1 << (8 - prefixlen);
786*10946SSangeeta.Misra@Sun.COM 		prefixlen--;
787*10946SSangeeta.Misra@Sun.COM 	}
788*10946SSangeeta.Misra@Sun.COM 	return (B_TRUE);
789*10946SSangeeta.Misra@Sun.COM }
790*10946SSangeeta.Misra@Sun.COM 
791*10946SSangeeta.Misra@Sun.COM ilbadm_status_t
ilbadm_set_netmask(char * val,ilb_ip_addr_t * ip,int af)792*10946SSangeeta.Misra@Sun.COM ilbadm_set_netmask(char *val, ilb_ip_addr_t *ip, int af)
793*10946SSangeeta.Misra@Sun.COM {
794*10946SSangeeta.Misra@Sun.COM 	int	prefixlen, maxval;
795*10946SSangeeta.Misra@Sun.COM 	boolean_t	r;
796*10946SSangeeta.Misra@Sun.COM 	char	*end;
797*10946SSangeeta.Misra@Sun.COM 
798*10946SSangeeta.Misra@Sun.COM 	assert(af == AF_INET || af == AF_INET6);
799*10946SSangeeta.Misra@Sun.COM 
800*10946SSangeeta.Misra@Sun.COM 	maxval = (af == AF_INET) ? 32 : 128;
801*10946SSangeeta.Misra@Sun.COM 
802*10946SSangeeta.Misra@Sun.COM 	if (*val == '/')
803*10946SSangeeta.Misra@Sun.COM 		val++;
804*10946SSangeeta.Misra@Sun.COM 	prefixlen = strtol(val, &end, 10);
805*10946SSangeeta.Misra@Sun.COM 	if ((val == end) || (*end != '\0')) {
806*10946SSangeeta.Misra@Sun.COM 		ilbadm_err(gettext("invalid pmask provided"));
807*10946SSangeeta.Misra@Sun.COM 		return (ILBADM_LIBERR);
808*10946SSangeeta.Misra@Sun.COM 	}
809*10946SSangeeta.Misra@Sun.COM 
810*10946SSangeeta.Misra@Sun.COM 	if (prefixlen < 1 || prefixlen > maxval) {
811*10946SSangeeta.Misra@Sun.COM 		ilbadm_err(gettext("invalid pmask provided (AF mismatch?)"));
812*10946SSangeeta.Misra@Sun.COM 		return (ILBADM_LIBERR);
813*10946SSangeeta.Misra@Sun.COM 	}
814*10946SSangeeta.Misra@Sun.COM 
815*10946SSangeeta.Misra@Sun.COM 	switch (af) {
816*10946SSangeeta.Misra@Sun.COM 	case AF_INET:
817*10946SSangeeta.Misra@Sun.COM 		r = in_prefixlentomask(prefixlen, maxval,
818*10946SSangeeta.Misra@Sun.COM 		    (uchar_t *)&ip->ia_v4.s_addr);
819*10946SSangeeta.Misra@Sun.COM 		break;
820*10946SSangeeta.Misra@Sun.COM 	case AF_INET6:
821*10946SSangeeta.Misra@Sun.COM 		r = in_prefixlentomask(prefixlen, maxval,
822*10946SSangeeta.Misra@Sun.COM 		    (uchar_t *)&ip->ia_v6.s6_addr);
823*10946SSangeeta.Misra@Sun.COM 		break;
824*10946SSangeeta.Misra@Sun.COM 	}
825*10946SSangeeta.Misra@Sun.COM 	if (r != B_TRUE) {
826*10946SSangeeta.Misra@Sun.COM 		ilbadm_err(gettext("cannot convert %s to a netmask"), val);
827*10946SSangeeta.Misra@Sun.COM 		return (ILBADM_LIBERR);
828*10946SSangeeta.Misra@Sun.COM 	}
829*10946SSangeeta.Misra@Sun.COM 	ip->ia_af = af;
830*10946SSangeeta.Misra@Sun.COM 	return (ILBADM_OK);
831*10946SSangeeta.Misra@Sun.COM }
832*10946SSangeeta.Misra@Sun.COM 
833*10946SSangeeta.Misra@Sun.COM static ilbadm_status_t
i_store_val(char * val,void * store,ilbadm_key_code_t keyword)834*10946SSangeeta.Misra@Sun.COM i_store_val(char *val, void *store, ilbadm_key_code_t keyword)
835*10946SSangeeta.Misra@Sun.COM {
836*10946SSangeeta.Misra@Sun.COM 	ilbadm_status_t	rc = ILBADM_OK;
837*10946SSangeeta.Misra@Sun.COM 	void		*storep = store;
838*10946SSangeeta.Misra@Sun.COM 	ilb_rule_data_t	*rd = NULL;
839*10946SSangeeta.Misra@Sun.COM 	ilbadm_sgroup_t	*sg = NULL;
840*10946SSangeeta.Misra@Sun.COM 	ilb_hc_info_t	*hc_info = NULL;
841*10946SSangeeta.Misra@Sun.COM 	struct protoent	*pe;
842*10946SSangeeta.Misra@Sun.COM 	int64_t		tmp_val;
843*10946SSangeeta.Misra@Sun.COM 
844*10946SSangeeta.Misra@Sun.COM 	if (*val == '\0')
845*10946SSangeeta.Misra@Sun.COM 		return (ILBADM_NOKEYWORD_VAL);
846*10946SSangeeta.Misra@Sun.COM 
847*10946SSangeeta.Misra@Sun.COM 	/* some types need new storage, others don't */
848*10946SSangeeta.Misra@Sun.COM 	switch (keyword) {
849*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_SERVER:
850*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_SERVERID:
851*10946SSangeeta.Misra@Sun.COM 		sg = (ilbadm_sgroup_t *)store;
852*10946SSangeeta.Misra@Sun.COM 		storep = i_new_storep(store, keyword);
853*10946SSangeeta.Misra@Sun.COM 		break;
854*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_HEALTHCHECK:
855*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_SERVERGROUP:
856*10946SSangeeta.Misra@Sun.COM 		rd = (ilb_rule_data_t *)store;
857*10946SSangeeta.Misra@Sun.COM 		break;
858*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_VIP:	/* fallthrough */
859*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_PORT:	/* fallthrough */
860*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_HCPORT:	/* fallthrough */
861*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_CONNDRAIN:	/* fallthrough */
862*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_NAT_TO:	/* fallthrough */
863*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_STICKY_TO:	/* fallthrough */
864*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_PROTOCOL:	/* fallthrough */
865*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_ALGORITHM:	/* fallthrough */
866*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_STICKY:	/* fallthrough */
867*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_TYPE:	/* fallthrough */
868*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_SRC:	/* fallthrough */
869*10946SSangeeta.Misra@Sun.COM 		rd = (ilb_rule_data_t *)store;
870*10946SSangeeta.Misra@Sun.COM 		break;
871*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_HC_TEST:
872*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_HC_COUNT:
873*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_HC_INTERVAL:
874*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_HC_TIMEOUT:
875*10946SSangeeta.Misra@Sun.COM 		hc_info = (ilb_hc_info_t *)store;
876*10946SSangeeta.Misra@Sun.COM 	default: /* do nothing */
877*10946SSangeeta.Misra@Sun.COM 		;
878*10946SSangeeta.Misra@Sun.COM 	}
879*10946SSangeeta.Misra@Sun.COM 
880*10946SSangeeta.Misra@Sun.COM 	switch (keyword) {
881*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_SRC:
882*10946SSangeeta.Misra@Sun.COM 		/*
883*10946SSangeeta.Misra@Sun.COM 		 * the proxy-src keyword is only valid for full NAT topology
884*10946SSangeeta.Misra@Sun.COM 		 * the value is either a single or a range of IP addresses.
885*10946SSangeeta.Misra@Sun.COM 		 */
886*10946SSangeeta.Misra@Sun.COM 		if (rd->r_topo != ILB_TOPO_NAT) {
887*10946SSangeeta.Misra@Sun.COM 			rc = ILBADM_INVAL_PROXY;
888*10946SSangeeta.Misra@Sun.COM 			break;
889*10946SSangeeta.Misra@Sun.COM 		}
890*10946SSangeeta.Misra@Sun.COM 		rc = i_match_hostorip(storep, sg, val, OPT_NUMERIC_ONLY |
891*10946SSangeeta.Misra@Sun.COM 		    OPT_IP_RANGE | OPT_NAT, ILB_KEY_SRC);
892*10946SSangeeta.Misra@Sun.COM 		break;
893*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_SERVER:
894*10946SSangeeta.Misra@Sun.COM 		rc = i_match_hostorip(storep, sg, val,
895*10946SSangeeta.Misra@Sun.COM 		    OPT_IP_RANGE | OPT_PORTS, ILB_KEY_SERVER);
896*10946SSangeeta.Misra@Sun.COM 		break;
897*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_SERVERID:
898*10946SSangeeta.Misra@Sun.COM 		if (val[0] != ILB_SRVID_PREFIX)
899*10946SSangeeta.Misra@Sun.COM 			rc = ILBADM_INVAL_SRVID;
900*10946SSangeeta.Misra@Sun.COM 		else
901*10946SSangeeta.Misra@Sun.COM 			rc = i_store_serverID(storep, val);
902*10946SSangeeta.Misra@Sun.COM 		break;
903*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_VIP: {
904*10946SSangeeta.Misra@Sun.COM 		ilb_ip_addr_t	*vip = &rd->r_vip;
905*10946SSangeeta.Misra@Sun.COM 		addr_type_t	at = numeric;
906*10946SSangeeta.Misra@Sun.COM 		char		*close = NULL;
907*10946SSangeeta.Misra@Sun.COM 
908*10946SSangeeta.Misra@Sun.COM 		/*
909*10946SSangeeta.Misra@Sun.COM 		 * we duplicate some functionality of i_match_hostorip
910*10946SSangeeta.Misra@Sun.COM 		 * here; that function is geared to mandate '[]' for IPv6
911*10946SSangeeta.Misra@Sun.COM 		 * addresses, which we want to relax here, so as not to
912*10946SSangeeta.Misra@Sun.COM 		 * make i_match_hostorip even longer, we do what we need
913*10946SSangeeta.Misra@Sun.COM 		 * here.
914*10946SSangeeta.Misra@Sun.COM 		 */
915*10946SSangeeta.Misra@Sun.COM 		if (*val == '[') {
916*10946SSangeeta.Misra@Sun.COM 			val++;
917*10946SSangeeta.Misra@Sun.COM 			if ((close = strchr(val, (int)']')) == NULL) {
918*10946SSangeeta.Misra@Sun.COM 				rc = ILBADM_INVAL_SYNTAX;
919*10946SSangeeta.Misra@Sun.COM 				break;
920*10946SSangeeta.Misra@Sun.COM 			}
921*10946SSangeeta.Misra@Sun.COM 			*close = NULL;
922*10946SSangeeta.Misra@Sun.COM 		}
923*10946SSangeeta.Misra@Sun.COM 		rc = i_match_onehost(val, vip, &at);
924*10946SSangeeta.Misra@Sun.COM 		/* re-assemble string as we found it */
925*10946SSangeeta.Misra@Sun.COM 		if (close != NULL) {
926*10946SSangeeta.Misra@Sun.COM 			*close = ']';
927*10946SSangeeta.Misra@Sun.COM 			if (rc == ILBADM_OK && vip->ia_af != AF_INET6) {
928*10946SSangeeta.Misra@Sun.COM 				ilbadm_err(gettext("use of '[]' only valid"
929*10946SSangeeta.Misra@Sun.COM 				    " with IPv6 addresses"));
930*10946SSangeeta.Misra@Sun.COM 				rc = ILBADM_LIBERR;
931*10946SSangeeta.Misra@Sun.COM 			}
932*10946SSangeeta.Misra@Sun.COM 		}
933*10946SSangeeta.Misra@Sun.COM 		break;
934*10946SSangeeta.Misra@Sun.COM 	}
935*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_CONNDRAIN:
936*10946SSangeeta.Misra@Sun.COM 		tmp_val = strtoll(val, NULL, 10);
937*10946SSangeeta.Misra@Sun.COM 		if (tmp_val <= 0 || tmp_val > UINT_MAX) {
938*10946SSangeeta.Misra@Sun.COM 			rc = ILBADM_EINVAL;
939*10946SSangeeta.Misra@Sun.COM 			break;
940*10946SSangeeta.Misra@Sun.COM 		}
941*10946SSangeeta.Misra@Sun.COM 		rd->r_conndrain = tmp_val;
942*10946SSangeeta.Misra@Sun.COM 		break;
943*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_NAT_TO:
944*10946SSangeeta.Misra@Sun.COM 		tmp_val = strtoll(val, NULL, 10);
945*10946SSangeeta.Misra@Sun.COM 		if (tmp_val < 0 || tmp_val > UINT_MAX) {
946*10946SSangeeta.Misra@Sun.COM 			rc = ILBADM_EINVAL;
947*10946SSangeeta.Misra@Sun.COM 			break;
948*10946SSangeeta.Misra@Sun.COM 		}
949*10946SSangeeta.Misra@Sun.COM 		rd->r_nat_timeout = tmp_val;
950*10946SSangeeta.Misra@Sun.COM 		break;
951*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_STICKY_TO:
952*10946SSangeeta.Misra@Sun.COM 		tmp_val = strtoll(val, NULL, 10);
953*10946SSangeeta.Misra@Sun.COM 		if (tmp_val <= 0 || tmp_val > UINT_MAX) {
954*10946SSangeeta.Misra@Sun.COM 			rc = ILBADM_EINVAL;
955*10946SSangeeta.Misra@Sun.COM 			break;
956*10946SSangeeta.Misra@Sun.COM 		}
957*10946SSangeeta.Misra@Sun.COM 		rd->r_sticky_timeout = tmp_val;
958*10946SSangeeta.Misra@Sun.COM 		break;
959*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_PORT:
960*10946SSangeeta.Misra@Sun.COM 		if (isdigit(*val)) {
961*10946SSangeeta.Misra@Sun.COM 			ilbadm_servnode_t	sn;
962*10946SSangeeta.Misra@Sun.COM 
963*10946SSangeeta.Misra@Sun.COM 			bzero(&sn, sizeof (sn));
964*10946SSangeeta.Misra@Sun.COM 			rc = i_match_hostorip((void *)&sn, sg, val,
965*10946SSangeeta.Misra@Sun.COM 			    OPT_PORTS_ONLY, ILB_KEY_PORT);
966*10946SSangeeta.Misra@Sun.COM 			if (rc != ILBADM_OK)
967*10946SSangeeta.Misra@Sun.COM 				break;
968*10946SSangeeta.Misra@Sun.COM 			rd->r_minport = sn.s_spec.sd_minport;
969*10946SSangeeta.Misra@Sun.COM 			rd->r_maxport = sn.s_spec.sd_maxport;
970*10946SSangeeta.Misra@Sun.COM 		} else {
971*10946SSangeeta.Misra@Sun.COM 			struct servent	*se;
972*10946SSangeeta.Misra@Sun.COM 
973*10946SSangeeta.Misra@Sun.COM 			se = getservbyname(val, NULL);
974*10946SSangeeta.Misra@Sun.COM 			if (se == NULL) {
975*10946SSangeeta.Misra@Sun.COM 				rc = ILBADM_ENOSERVICE;
976*10946SSangeeta.Misra@Sun.COM 				break;
977*10946SSangeeta.Misra@Sun.COM 			}
978*10946SSangeeta.Misra@Sun.COM 			rd->r_minport = se->s_port;
979*10946SSangeeta.Misra@Sun.COM 			rd->r_maxport = 0;
980*10946SSangeeta.Misra@Sun.COM 		}
981*10946SSangeeta.Misra@Sun.COM 		break;
982*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_HCPORT:
983*10946SSangeeta.Misra@Sun.COM 		if (isdigit(*val)) {
984*10946SSangeeta.Misra@Sun.COM 			int hcport = atoi(val);
985*10946SSangeeta.Misra@Sun.COM 
986*10946SSangeeta.Misra@Sun.COM 			if (hcport < 1 || hcport > 65535) {
987*10946SSangeeta.Misra@Sun.COM 				ilbadm_err(gettext("illegal number for"
988*10946SSangeeta.Misra@Sun.COM 				    " hcport %s"), val);
989*10946SSangeeta.Misra@Sun.COM 				rc = ILBADM_LIBERR;
990*10946SSangeeta.Misra@Sun.COM 				break;
991*10946SSangeeta.Misra@Sun.COM 			}
992*10946SSangeeta.Misra@Sun.COM 			rd->r_hcport = htons(hcport);
993*10946SSangeeta.Misra@Sun.COM 			rd->r_hcpflag = ILB_HCI_PROBE_FIX;
994*10946SSangeeta.Misra@Sun.COM 		} else if (strcasecmp(val, "ANY") == 0) {
995*10946SSangeeta.Misra@Sun.COM 			rd->r_hcport = 0;
996*10946SSangeeta.Misra@Sun.COM 			rd->r_hcpflag = ILB_HCI_PROBE_ANY;
997*10946SSangeeta.Misra@Sun.COM 		} else {
998*10946SSangeeta.Misra@Sun.COM 			return (ILBADM_EINVAL);
999*10946SSangeeta.Misra@Sun.COM 		}
1000*10946SSangeeta.Misra@Sun.COM 		break;
1001*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_PROTOCOL:
1002*10946SSangeeta.Misra@Sun.COM 		pe = getprotobyname(val);
1003*10946SSangeeta.Misra@Sun.COM 		if (pe == NULL)
1004*10946SSangeeta.Misra@Sun.COM 			rc = ILBADM_ENOPROTO;
1005*10946SSangeeta.Misra@Sun.COM 		else
1006*10946SSangeeta.Misra@Sun.COM 			rd->r_proto = pe->p_proto;
1007*10946SSangeeta.Misra@Sun.COM 		break;
1008*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_ALGORITHM:
1009*10946SSangeeta.Misra@Sun.COM 		rd->r_algo = i_val_from_str(val, &algo_types[0]);
1010*10946SSangeeta.Misra@Sun.COM 		if (rd->r_algo == ILBD_BAD_VAL)
1011*10946SSangeeta.Misra@Sun.COM 			rc = ILBADM_INVAL_ALG;
1012*10946SSangeeta.Misra@Sun.COM 		break;
1013*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_STICKY:
1014*10946SSangeeta.Misra@Sun.COM 		rd->r_flags |= ILB_FLAGS_RULE_STICKY;
1015*10946SSangeeta.Misra@Sun.COM 		/*
1016*10946SSangeeta.Misra@Sun.COM 		 * CAVEAT: the use of r_vip.ia_af implies that the VIP
1017*10946SSangeeta.Misra@Sun.COM 		 * *must* be specified on the commandline *before*
1018*10946SSangeeta.Misra@Sun.COM 		 * the sticky mask.
1019*10946SSangeeta.Misra@Sun.COM 		 */
1020*10946SSangeeta.Misra@Sun.COM 		if (AF_UNSPEC == rd->r_vip.ia_af) {
1021*10946SSangeeta.Misra@Sun.COM 			ilbadm_err(gettext("option '%s' requires that VIP be "
1022*10946SSangeeta.Misra@Sun.COM 			    "specified first"), ilbadm_key_to_opt(keyword));
1023*10946SSangeeta.Misra@Sun.COM 			rc = ILBADM_LIBERR;
1024*10946SSangeeta.Misra@Sun.COM 			break;
1025*10946SSangeeta.Misra@Sun.COM 		}
1026*10946SSangeeta.Misra@Sun.COM 		rc = ilbadm_set_netmask(val, &rd->r_stickymask,
1027*10946SSangeeta.Misra@Sun.COM 		    rd->r_vip.ia_af);
1028*10946SSangeeta.Misra@Sun.COM 		break;
1029*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_TYPE:
1030*10946SSangeeta.Misra@Sun.COM 		rd->r_topo = i_val_from_str(val, &topo_types[0]);
1031*10946SSangeeta.Misra@Sun.COM 		if (rd->r_topo == ILBD_BAD_VAL)
1032*10946SSangeeta.Misra@Sun.COM 			rc = ILBADM_INVAL_OPER;
1033*10946SSangeeta.Misra@Sun.COM 		break;
1034*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_SERVERGROUP:
1035*10946SSangeeta.Misra@Sun.COM 		(void) strlcpy(rd->r_sgname, (char *)val,
1036*10946SSangeeta.Misra@Sun.COM 		    sizeof (rd->r_sgname));
1037*10946SSangeeta.Misra@Sun.COM 		break;
1038*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_HEALTHCHECK:
1039*10946SSangeeta.Misra@Sun.COM 		(void) strlcpy(rd->r_hcname, (char *)val,
1040*10946SSangeeta.Misra@Sun.COM 		    sizeof (rd->r_hcname));
1041*10946SSangeeta.Misra@Sun.COM 		break;
1042*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_HC_TEST:
1043*10946SSangeeta.Misra@Sun.COM 		(void) strlcpy(hc_info->hci_test, (char *)val,
1044*10946SSangeeta.Misra@Sun.COM 		    sizeof (hc_info->hci_test));
1045*10946SSangeeta.Misra@Sun.COM 		break;
1046*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_HC_COUNT:
1047*10946SSangeeta.Misra@Sun.COM 		if (isdigit(*val))
1048*10946SSangeeta.Misra@Sun.COM 			hc_info->hci_count = atoi(val);
1049*10946SSangeeta.Misra@Sun.COM 		else
1050*10946SSangeeta.Misra@Sun.COM 			return (ILBADM_EINVAL);
1051*10946SSangeeta.Misra@Sun.COM 		break;
1052*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_HC_INTERVAL:
1053*10946SSangeeta.Misra@Sun.COM 		if (isdigit(*val))
1054*10946SSangeeta.Misra@Sun.COM 			hc_info->hci_interval = atoi(val);
1055*10946SSangeeta.Misra@Sun.COM 		else
1056*10946SSangeeta.Misra@Sun.COM 			return (ILBADM_EINVAL);
1057*10946SSangeeta.Misra@Sun.COM 		break;
1058*10946SSangeeta.Misra@Sun.COM 	case ILB_KEY_HC_TIMEOUT:
1059*10946SSangeeta.Misra@Sun.COM 		if (isdigit(*val))
1060*10946SSangeeta.Misra@Sun.COM 			hc_info->hci_timeout = atoi(val);
1061*10946SSangeeta.Misra@Sun.COM 		else
1062*10946SSangeeta.Misra@Sun.COM 			return (ILBADM_EINVAL);
1063*10946SSangeeta.Misra@Sun.COM 		break;
1064*10946SSangeeta.Misra@Sun.COM 	default: rc = ILBADM_INVAL_KEYWORD;
1065*10946SSangeeta.Misra@Sun.COM 		break;
1066*10946SSangeeta.Misra@Sun.COM 	}
1067*10946SSangeeta.Misra@Sun.COM 
1068*10946SSangeeta.Misra@Sun.COM 	return (rc);
1069*10946SSangeeta.Misra@Sun.COM }
1070*10946SSangeeta.Misra@Sun.COM 
1071*10946SSangeeta.Misra@Sun.COM /*
1072*10946SSangeeta.Misra@Sun.COM  * generic parsing function.
1073*10946SSangeeta.Misra@Sun.COM  * parses "key=value[,value]" strings in "arg". keylist determines the
1074*10946SSangeeta.Misra@Sun.COM  * list of valid keys in the LHS. keycode determines interpretation and
1075*10946SSangeeta.Misra@Sun.COM  * storage in store
1076*10946SSangeeta.Misra@Sun.COM  * XXXms: looks like "key=value[,value]" violates spec. needs a fix
1077*10946SSangeeta.Misra@Sun.COM  */
1078*10946SSangeeta.Misra@Sun.COM ilbadm_status_t
i_parse_optstring(char * arg,void * store,ilbadm_key_name_t * keylist,int flags,int * count)1079*10946SSangeeta.Misra@Sun.COM i_parse_optstring(char *arg, void *store, ilbadm_key_name_t *keylist,
1080*10946SSangeeta.Misra@Sun.COM     int flags, int *count)
1081*10946SSangeeta.Misra@Sun.COM {
1082*10946SSangeeta.Misra@Sun.COM 	ilbadm_status_t	rc = ILBADM_OK;
1083*10946SSangeeta.Misra@Sun.COM 	char		*comma = NULL, *equals = NULL;
1084*10946SSangeeta.Misra@Sun.COM 	char		*key, *nextkey, *val;
1085*10946SSangeeta.Misra@Sun.COM 	ilbadm_key_code_t	keyword;
1086*10946SSangeeta.Misra@Sun.COM 	boolean_t	is_value_list = flags & OPT_VALUE_LIST;
1087*10946SSangeeta.Misra@Sun.COM 	boolean_t	assign_seen = B_FALSE;
1088*10946SSangeeta.Misra@Sun.COM 	int		n;
1089*10946SSangeeta.Misra@Sun.COM 
1090*10946SSangeeta.Misra@Sun.COM 	key = arg;
1091*10946SSangeeta.Misra@Sun.COM 	n = 1;
1092*10946SSangeeta.Misra@Sun.COM 	/*
1093*10946SSangeeta.Misra@Sun.COM 	 * Algorithm:
1094*10946SSangeeta.Misra@Sun.COM 	 * 1. find any commas indicating and seperating current value
1095*10946SSangeeta.Misra@Sun.COM 	 *    from a following value
1096*10946SSangeeta.Misra@Sun.COM 	 * 2. if we're expecting a list of values (seperated by commas)
1097*10946SSangeeta.Misra@Sun.COM 	 *	and have already seen the assignment, then
1098*10946SSangeeta.Misra@Sun.COM 	 *	get the next "value"
1099*10946SSangeeta.Misra@Sun.COM 	 * 3. else (we're looking at the first element of the RHS)
1100*10946SSangeeta.Misra@Sun.COM 	 *	4. find the '='
1101*10946SSangeeta.Misra@Sun.COM 	 *	5. match the keyword to the list we were passed in
1102*10946SSangeeta.Misra@Sun.COM 	 * 6. store the value.
1103*10946SSangeeta.Misra@Sun.COM 	 */
1104*10946SSangeeta.Misra@Sun.COM 	while (key != NULL && *key != '\0') {
1105*10946SSangeeta.Misra@Sun.COM 		comma = equals = NULL;
1106*10946SSangeeta.Misra@Sun.COM 
1107*10946SSangeeta.Misra@Sun.COM 		/* 2 */
1108*10946SSangeeta.Misra@Sun.COM 		nextkey = strchr(key, (int)',');
1109*10946SSangeeta.Misra@Sun.COM 		if (nextkey != NULL) {
1110*10946SSangeeta.Misra@Sun.COM 			comma = nextkey++;
1111*10946SSangeeta.Misra@Sun.COM 			*comma = '\0';
1112*10946SSangeeta.Misra@Sun.COM 		}
1113*10946SSangeeta.Misra@Sun.COM 
1114*10946SSangeeta.Misra@Sun.COM 		/* 3a */
1115*10946SSangeeta.Misra@Sun.COM 		if (is_value_list && assign_seen) {
1116*10946SSangeeta.Misra@Sun.COM 			val = key;
1117*10946SSangeeta.Misra@Sun.COM 		/* 3b */
1118*10946SSangeeta.Misra@Sun.COM 		} else {
1119*10946SSangeeta.Misra@Sun.COM 			/* 4 */
1120*10946SSangeeta.Misra@Sun.COM 			equals = strchr(key, (int)'=');
1121*10946SSangeeta.Misra@Sun.COM 			if (equals == NULL) {
1122*10946SSangeeta.Misra@Sun.COM 				ilbadm_err("%s: %s", key,
1123*10946SSangeeta.Misra@Sun.COM 				    ilbadm_errstr(ILBADM_ASSIGNREQ));
1124*10946SSangeeta.Misra@Sun.COM 				rc = ILBADM_LIBERR;
1125*10946SSangeeta.Misra@Sun.COM 				goto out;
1126*10946SSangeeta.Misra@Sun.COM 			}
1127*10946SSangeeta.Misra@Sun.COM 			val = equals + 1;
1128*10946SSangeeta.Misra@Sun.COM 			*equals = '\0';
1129*10946SSangeeta.Misra@Sun.COM 			assign_seen = B_TRUE;
1130*10946SSangeeta.Misra@Sun.COM 
1131*10946SSangeeta.Misra@Sun.COM 			/* 5 */
1132*10946SSangeeta.Misra@Sun.COM 			keyword = i_match_key(key, keylist);
1133*10946SSangeeta.Misra@Sun.COM 			if (keyword == ILB_KEY_BAD) {
1134*10946SSangeeta.Misra@Sun.COM 				ilbadm_err(gettext("bad keyword %s"), key);
1135*10946SSangeeta.Misra@Sun.COM 				rc = ILBADM_LIBERR;
1136*10946SSangeeta.Misra@Sun.COM 				goto out;
1137*10946SSangeeta.Misra@Sun.COM 			}
1138*10946SSangeeta.Misra@Sun.COM 		}
1139*10946SSangeeta.Misra@Sun.COM 
1140*10946SSangeeta.Misra@Sun.COM 		/* 6 */
1141*10946SSangeeta.Misra@Sun.COM 		rc = i_store_val(val, store, keyword);
1142*10946SSangeeta.Misra@Sun.COM 		if (rc != ILBADM_OK) {
1143*10946SSangeeta.Misra@Sun.COM 			ilbadm_err("%s: %s", key, ilbadm_errstr(rc));
1144*10946SSangeeta.Misra@Sun.COM 			/* Change to ILBADM_ILBERR to avoid more err msgs. */
1145*10946SSangeeta.Misra@Sun.COM 			rc = ILBADM_LIBERR;
1146*10946SSangeeta.Misra@Sun.COM 			goto out;
1147*10946SSangeeta.Misra@Sun.COM 		}
1148*10946SSangeeta.Misra@Sun.COM 
1149*10946SSangeeta.Misra@Sun.COM 		key = nextkey;
1150*10946SSangeeta.Misra@Sun.COM 		n++;
1151*10946SSangeeta.Misra@Sun.COM 	}
1152*10946SSangeeta.Misra@Sun.COM 
1153*10946SSangeeta.Misra@Sun.COM out:
1154*10946SSangeeta.Misra@Sun.COM 	if (comma != NULL)
1155*10946SSangeeta.Misra@Sun.COM 		*comma = ',';
1156*10946SSangeeta.Misra@Sun.COM 	if (equals != NULL)
1157*10946SSangeeta.Misra@Sun.COM 		*equals = '=';
1158*10946SSangeeta.Misra@Sun.COM 	if (count != NULL)
1159*10946SSangeeta.Misra@Sun.COM 		*count = n;
1160*10946SSangeeta.Misra@Sun.COM 	return (rc);
1161*10946SSangeeta.Misra@Sun.COM }
1162