1 /* source: xio-ip6.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
4 
5 /* this file contains the source for IP6 related functions */
6 
7 #include "xiosysincludes.h"
8 
9 #if WITH_IP6
10 
11 #include "xioopen.h"
12 #include "xio-ascii.h"
13 #include "xio-socket.h"
14 #include "xio-ip.h"	/* xiogetaddrinfo() */
15 
16 #include "xio-ip6.h"
17 
18 
19 static char *inet6addr_info(const struct in6_addr *sa, char *buff, size_t blen);
20 
21 
22 #ifdef IPV6_V6ONLY
23 const struct optdesc opt_ipv6_v6only = { "ipv6-v6only", "ipv6only", OPT_IPV6_V6ONLY, GROUP_SOCK_IP6, PH_PREBIND, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_V6ONLY };
24 #endif
25 #ifdef IPV6_JOIN_GROUP
26 const struct optdesc opt_ipv6_join_group = { "ipv6-join-group", "join-group", OPT_IPV6_JOIN_GROUP, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_IP_MREQN, OFUNC_SOCKOPT, SOL_IPV6, IPV6_JOIN_GROUP };
27 #endif
28 #ifdef IPV6_PKTINFO
29 const struct optdesc opt_ipv6_pktinfo = { "ipv6-pktinfo", "pktinfo", OPT_IPV6_PKTINFO, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_PKTINFO };
30 #endif
31 #ifdef IPV6_RECVPKTINFO
32 const struct optdesc opt_ipv6_recvpktinfo = { "ipv6-recvpktinfo", "recvpktinfo", OPT_IPV6_RECVPKTINFO, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVPKTINFO };
33 #endif
34 #ifdef IPV6_RTHDR
35 const struct optdesc opt_ipv6_rthdr   = { "ipv6-rthdr",   "rthdr",   OPT_IPV6_RTHDR,   GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RTHDR };
36 #endif
37 #ifdef IPV6_RECVRTHDR
38 const struct optdesc opt_ipv6_recvrthdr   = { "ipv6-recvrthdr",   "recvrthdr",   OPT_IPV6_RECVRTHDR,   GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVRTHDR };
39 #endif
40 #ifdef IPV6_AUTHHDR
41 const struct optdesc opt_ipv6_authhdr = { "ipv6-authhdr", "authhdr", OPT_IPV6_AUTHHDR, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_AUTHHDR };
42 #endif
43 #ifdef IPV6_DSTOPTS
44 const struct optdesc opt_ipv6_dstopts = { "ipv6-dstopts", "dstopts", OPT_IPV6_DSTOPTS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_DSTOPTS };
45 #endif
46 #ifdef IPV6_RECVDSTOPTS
47 const struct optdesc opt_ipv6_recvdstopts = { "ipv6-recvdstopts", "recvdstopts", OPT_IPV6_RECVDSTOPTS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVDSTOPTS };
48 #endif
49 #ifdef IPV6_HOPOPTS
50 const struct optdesc opt_ipv6_hopopts = { "ipv6-hopopts", "hopopts", OPT_IPV6_HOPOPTS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_HOPOPTS };
51 #endif
52 #ifdef IPV6_RECVHOPOPTS
53 const struct optdesc opt_ipv6_recvhopopts = { "ipv6-recvhopopts", "recvhopopts", OPT_IPV6_RECVHOPOPTS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVHOPOPTS };
54 #endif
55 #ifdef IPV6_FLOWINFO /* is in linux/in6.h */
56 const struct optdesc opt_ipv6_flowinfo= { "ipv6-flowinfo","flowinfo",OPT_IPV6_FLOWINFO,GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_FLOWINFO };
57 #endif
58 #ifdef IPV6_HOPLIMIT
59 const struct optdesc opt_ipv6_hoplimit= { "ipv6-hoplimit","hoplimit",OPT_IPV6_HOPLIMIT,GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_HOPLIMIT };
60 #endif
61 const struct optdesc opt_ipv6_unicast_hops= { "ipv6-unicast-hops","unicast-hops",OPT_IPV6_UNICAST_HOPS,GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_UNICAST_HOPS };
62 #ifdef IPV6_RECVHOPLIMIT
63 const struct optdesc opt_ipv6_recvhoplimit= { "ipv6-recvhoplimit","recvhoplimit",OPT_IPV6_RECVHOPLIMIT,GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVHOPLIMIT };
64 #endif
65 #ifdef IPV6_RECVERR
66 const struct optdesc opt_ipv6_recverr = { "ipv6-recverr", "recverr", OPT_IPV6_RECVERR, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVERR };
67 #endif
68 #ifdef IPV6_TCLASS
69 const struct optdesc opt_ipv6_tclass     = { "ipv6-tclass",     "tclass",     OPT_IPV6_TCLASS,     GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT,  OFUNC_SOCKOPT, SOL_IPV6, IPV6_TCLASS };
70 #endif
71 #ifdef IPV6_RECVTCLASS
72 const struct optdesc opt_ipv6_recvtclass = { "ipv6-recvtclass", "recvtclass", OPT_IPV6_RECVTCLASS, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVTCLASS };
73 #endif
74 #ifdef IPV6_RECVPATHMTU
75 const struct optdesc opt_ipv6_recvpathmtu = { "ipv6-recvpathmtu", "recvpathmtu", OPT_IPV6_RECVPATHMTU, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_IPV6, IPV6_RECVPATHMTU };
76 #endif
77 
78 /* Returns canonical form of IPv6 address.
79    IPv6 address may bei enclose in brackets.
80    Returns STAT_OK on success, STAT_NORETRY on failure. */
xioip6_pton(const char * src,struct in6_addr * dst)81 int xioip6_pton(const char *src, struct in6_addr *dst) {
82    union sockaddr_union sockaddr;
83    socklen_t sockaddrlen = sizeof(sockaddr);
84 
85    if (src[0] == '[') {
86       char plainaddr[INET6_ADDRSTRLEN];
87       char *clos;
88 
89       strncpy(plainaddr, src+1, INET6_ADDRSTRLEN);
90       plainaddr[INET6_ADDRSTRLEN-1] = '\0';
91       if ((clos = strchr(plainaddr, ']')) != NULL)
92 	 *clos = '\0';
93       return xioip6_pton(plainaddr, dst);
94    }
95    if (xiogetaddrinfo(src, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen,
96 		      0, 0)
97        != STAT_OK) {
98       return STAT_NORETRY;
99    }
100    *dst = sockaddr.ip6.sin6_addr;
101    return STAT_OK;
102 }
103 
xioparsenetwork_ip6(const char * rangename,struct xiorange * range)104 int xioparsenetwork_ip6(const char *rangename, struct xiorange *range) {
105    char *delimpos;	/* absolute address of delimiter */
106    size_t delimind;	/* index of delimiter in string */
107    unsigned int bits;	/* netmask bits */
108    char *endptr;
109    char *baseaddr;
110    union sockaddr_union sockaddr;
111    socklen_t sockaddrlen = sizeof(sockaddr);
112    union xioin6_u *rangeaddr = (union xioin6_u *)&range->netaddr.ip6.sin6_addr;
113    union xioin6_u *rangemask = (union xioin6_u *)&range->netmask.ip6.sin6_addr;
114    union xioin6_u *nameaddr = (union xioin6_u *)&sockaddr.ip6.sin6_addr;
115 
116    if ((delimpos = strchr(rangename, '/')) == NULL) {
117       Error1("xioparsenetwork_ip6(\"%s\",,): missing mask bits delimiter '/'",
118 	     rangename);
119       return STAT_NORETRY;
120    }
121    delimind = delimpos - rangename;
122    if (rangename[0] != '[' || rangename[delimind-1] != ']') {
123       Error1("missing brackets for IPv6 range definition \"%s\"",
124 	     rangename);
125       return STAT_NORETRY;
126    }
127 
128    if ((baseaddr = strndup(rangename+1,delimind-2)) == NULL) {
129       Error1("strdup(\"%s\"): out of memory", rangename+1);
130       return STAT_NORETRY;
131    }
132    baseaddr[delimind-2] = '\0';
133    if (xiogetaddrinfo(baseaddr, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen,
134 		      0, 0)
135        != STAT_OK) {
136       return STAT_NORETRY;
137    }
138    rangeaddr->u6_addr32[0] = nameaddr->u6_addr32[0];
139    rangeaddr->u6_addr32[1] = nameaddr->u6_addr32[1];
140    rangeaddr->u6_addr32[2] = nameaddr->u6_addr32[2];
141    rangeaddr->u6_addr32[3] = nameaddr->u6_addr32[3];
142    bits = strtoul(delimpos+1, &endptr, 10);
143    if (! ((*(delimpos+1) != '\0') && (*endptr == '\0'))) {
144       Error1("not a valid netmask in \"%s\"", rangename);
145       bits = 128;	/* most secure selection */
146    } else if (bits > 128) {
147       Error1("netmask \"%s\" is too large", rangename);
148       bits = 128;
149    }
150 
151    /* I am starting to dislike C...uint32_t << 32 is undefined... */
152    if (bits == 0) {
153       rangemask->u6_addr32[0] = 0;
154       rangemask->u6_addr32[1] = 0;
155       rangemask->u6_addr32[2] = 0;
156       rangemask->u6_addr32[3] = 0;
157    } else if (bits <= 32) {
158       rangemask->u6_addr32[0] = htonl(0xffffffff << (32-bits));
159       rangemask->u6_addr32[1] = 0;
160       rangemask->u6_addr32[2] = 0;
161       rangemask->u6_addr32[3] = 0;
162    } else if (bits <= 64) {
163       rangemask->u6_addr32[0] = 0xffffffff;
164       rangemask->u6_addr32[1] = htonl(0xffffffff << (64-bits));
165       rangemask->u6_addr32[2] = 0;
166       rangemask->u6_addr32[3] = 0;
167    } else if (bits <= 96) {
168       rangemask->u6_addr32[0] = 0xffffffff;
169       rangemask->u6_addr32[1] = 0xffffffff;
170       rangemask->u6_addr32[2] = htonl(0xffffffff << (96-bits));
171       rangemask->u6_addr32[3] = 0;
172    } else {
173       rangemask->u6_addr32[0] = 0xffffffff;
174       rangemask->u6_addr32[1] = 0xffffffff;
175       rangemask->u6_addr32[2] = 0xffffffff;
176       rangemask->u6_addr32[3] = htonl(0xffffffff << (128-bits));
177    }
178    return 0;
179 }
180 
xiorange_ip6andmask(struct xiorange * range)181 int xiorange_ip6andmask(struct xiorange *range) {
182    int i;
183 #if 0
184    range->addr.s6_addr32[0] &= range->mask.s6_addr32[0];
185    range->addr.s6_addr32[1] &= range->mask.s6_addr32[1];
186    range->addr.s6_addr32[2] &= range->mask.s6_addr32[2];
187    range->addr.s6_addr32[3] &= range->mask.s6_addr32[3];
188 #else
189    for (i = 0; i < 16; ++i) {
190       range->netaddr.ip6.sin6_addr.s6_addr[i] &=
191 	 range->netmask.ip6.sin6_addr.s6_addr[i];
192    }
193 #endif
194    return 0;
195 }
196 
197 /* check if peer address is within permitted range.
198    return >= 0 if so. */
xiocheckrange_ip6(struct sockaddr_in6 * pa,struct xiorange * range)199 int xiocheckrange_ip6(struct sockaddr_in6 *pa, struct xiorange *range) {
200    union xioin6_u masked;
201    int i;
202    char peername[256];
203    union xioin6_u *rangeaddr = (union xioin6_u *)&range->netaddr.ip6.sin6_addr;
204    union xioin6_u *rangemask = (union xioin6_u *)&range->netmask.ip6.sin6_addr;
205 
206    Debug16("permitted client subnet: [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
207 	   htons(rangeaddr->u6_addr16[0]),  htons(rangeaddr->u6_addr16[1]),
208 	   htons(rangeaddr->u6_addr16[2]),  htons(rangeaddr->u6_addr16[3]),
209 	   htons(rangeaddr->u6_addr16[4]),  htons(rangeaddr->u6_addr16[5]),
210 	   htons(rangeaddr->u6_addr16[6]),  htons(rangeaddr->u6_addr16[7]),
211 	   htons(rangemask->u6_addr16[0]),  htons(rangemask->u6_addr16[1]),
212 	   htons(rangemask->u6_addr16[2]),  htons(rangemask->u6_addr16[3]),
213 	   htons(rangemask->u6_addr16[4]),  htons(rangemask->u6_addr16[5]),
214 	   htons(rangemask->u6_addr16[6]),  htons(rangemask->u6_addr16[7]));
215    Debug1("client address is %s",
216 	  sockaddr_inet6_info(pa, peername, sizeof(peername)));
217 
218    for (i = 0; i < 4; ++i) {
219       masked.u6_addr32[i] = ((union xioin6_u *)&pa->sin6_addr.s6_addr[0])->u6_addr32[i] & rangemask->u6_addr32[i];
220    }
221    Debug8("masked address is [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
222 	   htons(masked.u6_addr16[0]),  htons(masked.u6_addr16[1]),
223 	   htons(masked.u6_addr16[2]),  htons(masked.u6_addr16[3]),
224 	   htons(masked.u6_addr16[4]),  htons(masked.u6_addr16[5]),
225 	   htons(masked.u6_addr16[6]),  htons(masked.u6_addr16[7]));
226 
227    if (masked.u6_addr32[0] != rangeaddr->u6_addr32[0] ||
228        masked.u6_addr32[1] != rangeaddr->u6_addr32[1] ||
229        masked.u6_addr32[2] != rangeaddr->u6_addr32[2] ||
230        masked.u6_addr32[3] != rangeaddr->u6_addr32[3]) {
231       Debug1("client address %s is not permitted", peername);
232       return -1;
233    }
234    return 0;
235 }
236 
237 
238 #if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
239 /* provides info about the ancillary message:
240    converts the ancillary message in *cmsg into a form useable for further
241    processing. knows the specifics of common message types.
242    returns the number of resulting syntax elements in *num
243    returns a sequence of \0 terminated type strings in *typbuff
244    returns a sequence of \0 terminated name strings in *nambuff
245    returns a sequence of \0 terminated value strings in *valbuff
246    the respective len parameters specify the available space in the buffers
247    returns STAT_OK on success
248  */
xiolog_ancillary_ip6(struct cmsghdr * cmsg,int * num,char * typbuff,int typlen,char * nambuff,int namlen,char * envbuff,int envlen,char * valbuff,int vallen)249 int xiolog_ancillary_ip6(struct cmsghdr *cmsg, int *num,
250 			 char *typbuff, int typlen,
251 			 char *nambuff, int namlen,
252 			 char *envbuff, int envlen,
253 			 char *valbuff, int vallen) {
254    char scratch1[42];	/* can hold an IPv6 address in ASCII */
255    char scratch2[32];
256    size_t msglen;
257 
258    *num = 1;	/* good for most message types */
259    msglen = cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg);
260       envbuff[0] = '\0';
261    switch (cmsg->cmsg_type) {
262 #if defined(IPV6_PKTINFO) && HAVE_STRUCT_IN6_PKTINFO
263    case IPV6_PKTINFO: {
264       struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
265       *num = 2;
266       typbuff[0] = '\0'; strncat(typbuff, "IPV6_PKTINFO", typlen-1);
267       snprintf(nambuff, namlen, "%s%c%s", "dstaddr", '\0', "if");
268       snprintf(envbuff, envlen, "%s%c%s", "IPV6_DSTADDR", '\0', "IPV6_IF");
269       snprintf(valbuff, vallen, "%s%c%s",
270 	       inet6addr_info(&pktinfo->ipi6_addr, scratch1, sizeof(scratch1)),
271 	       '\0', xiogetifname(pktinfo->ipi6_ifindex, scratch2, -1));
272    }
273       return STAT_OK;
274 #endif /* defined(IPV6_PKTINFO) && HAVE_STRUCT_IN6_PKTINFO */
275 #ifdef IPV6_HOPLIMIT
276    case IPV6_HOPLIMIT:
277       typbuff[0] = '\0'; strncat(typbuff, "IPV6_HOPLIMIT", typlen-1);
278       nambuff[0] = '\0'; strncat(nambuff, "hoplimit", namlen-1);
279       {
280 	 int *intp = (int *)CMSG_DATA(cmsg);
281 	 snprintf(valbuff, vallen, "%d", *intp);
282       }
283       return STAT_OK;
284 #endif /* defined(IPV6_HOPLIMIT) */
285 #ifdef IPV6_RTHDR
286    case IPV6_RTHDR:
287       typbuff[0] = '\0'; strncat(typbuff, "IPV6_RTHDR", typlen-1);
288       nambuff[0] = '\0'; strncat(nambuff, "rthdr", namlen-1);
289       xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
290       return STAT_OK;
291 #endif /* defined(IPV6_RTHDR) */
292 #ifdef IPV6_AUTHHDR
293    case IPV6_AUTHHDR:
294       typbuff[0] = '\0'; strncat(typbuff, "IPV6_AUTHHDR", typlen-1);
295       nambuff[0] = '\0'; strncat(nambuff, "authhdr", namlen-1);
296       xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
297       return STAT_OK;
298 #endif
299 #ifdef IPV6_DSTOPTS
300    case IPV6_DSTOPTS:
301       typbuff[0] = '\0'; strncat(typbuff, "IPV6_DSTOPTS", typlen-1);
302       nambuff[0] = '\0'; strncat(nambuff, "dstopts", namlen-1);
303       xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
304       return STAT_OK;
305 #endif /* defined(IPV6_DSTOPTS) */
306 #ifdef IPV6_HOPOPTS
307    case IPV6_HOPOPTS:
308       typbuff[0] = '\0'; strncat(typbuff, "IPV6_HOPOPTS", typlen-1);
309       nambuff[0] = '\0'; strncat(nambuff, "hopopts", namlen-1);
310       xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
311       return STAT_OK;
312 #endif /* defined(IPV6_HOPOPTS) */
313 #ifdef IPV6_FLOWINFO
314    case IPV6_FLOWINFO:
315       typbuff[0] = '\0'; strncat(typbuff, "IPV6_FLOWINFO", typlen-1);
316       nambuff[0] = '\0'; strncat(nambuff, "flowinfo", namlen-1);
317       xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
318       return STAT_OK;
319 #endif
320 #ifdef IPV6_TCLASS
321    case IPV6_TCLASS: {
322       unsigned int u;
323       typbuff[0] = '\0'; strncat(typbuff, "IPV6_TCLASS", typlen-1);
324       nambuff[0] = '\0'; strncat(nambuff, "tclass", namlen-1);
325       u = ntohl(*(unsigned int *)CMSG_DATA(cmsg));
326       xiodump((const unsigned char *)&u, msglen, valbuff, vallen, 0);
327       return STAT_OK;
328    }
329 #endif
330    default:
331       snprintf(typbuff, typlen, "IPV6.%u", cmsg->cmsg_type);
332       nambuff[0] = '\0'; strncat(nambuff, "data", namlen-1);
333       xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
334       return STAT_OK;
335    }
336    return STAT_OK;
337 }
338 #endif /* defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) */
339 
340 
341 /* convert the IP6 socket address to human readable form. buff should be at
342    least 50 chars long. output includes the port number */
inet6addr_info(const struct in6_addr * sa,char * buff,size_t blen)343 static char *inet6addr_info(const struct in6_addr *sa, char *buff, size_t blen) {
344    if (xio_snprintf(buff, blen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
345 #if HAVE_IP6_SOCKADDR==0
346 		(sa->s6_addr[0]<<8)+sa->s6_addr[1],
347 		(sa->s6_addr[2]<<8)+sa->s6_addr[3],
348 		(sa->s6_addr[4]<<8)+sa->s6_addr[5],
349 		(sa->s6_addr[6]<<8)+sa->s6_addr[7],
350 		(sa->s6_addr[8]<<8)+sa->s6_addr[9],
351 		(sa->s6_addr[10]<<8)+sa->s6_addr[11],
352 		(sa->s6_addr[12]<<8)+sa->s6_addr[13],
353 		(sa->s6_addr[14]<<8)+sa->s6_addr[15]
354 #elif HAVE_IP6_SOCKADDR==1
355 		ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[0]),
356 		ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[1]),
357 		ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[2]),
358 		ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[3]),
359 		ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[4]),
360 		ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[5]),
361 		ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[6]),
362 		ntohs(((unsigned short *)&sa->u6_addr.u6_addr16)[7])
363 #elif HAVE_IP6_SOCKADDR==2
364 		ntohs(((unsigned short *)&sa->u6_addr16)[0]),
365 		ntohs(((unsigned short *)&sa->u6_addr16)[1]),
366 		ntohs(((unsigned short *)&sa->u6_addr16)[2]),
367 		ntohs(((unsigned short *)&sa->u6_addr16)[3]),
368 		ntohs(((unsigned short *)&sa->u6_addr16)[4]),
369 		ntohs(((unsigned short *)&sa->u6_addr16)[5]),
370 		ntohs(((unsigned short *)&sa->u6_addr16)[6]),
371 		ntohs(((unsigned short *)&sa->u6_addr16)[7])
372 #elif HAVE_IP6_SOCKADDR==3
373 		ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[0]),
374 		ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[1]),
375 		ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[2]),
376 		ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[3]),
377 		ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[4]),
378 		ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[5]),
379 		ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[6]),
380 		ntohs(((unsigned short *)&sa->in6_u.u6_addr16)[7])
381 #elif HAVE_IP6_SOCKADDR==4
382 		(sa->_S6_un._S6_u8[0]<<8)|(sa->_S6_un._S6_u8[1]&0xff),
383 		(sa->_S6_un._S6_u8[2]<<8)|(sa->_S6_un._S6_u8[3]&0xff),
384 		(sa->_S6_un._S6_u8[4]<<8)|(sa->_S6_un._S6_u8[5]&0xff),
385 		(sa->_S6_un._S6_u8[6]<<8)|(sa->_S6_un._S6_u8[7]&0xff),
386 		(sa->_S6_un._S6_u8[8]<<8)|(sa->_S6_un._S6_u8[9]&0xff),
387 		(sa->_S6_un._S6_u8[10]<<8)|(sa->_S6_un._S6_u8[11]&0xff),
388 		(sa->_S6_un._S6_u8[12]<<8)|(sa->_S6_un._S6_u8[13]&0xff),
389 		(sa->_S6_un._S6_u8[14]<<8)|(sa->_S6_un._S6_u8[15]&0xff)
390 #elif HAVE_IP6_SOCKADDR==5
391 		ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[0]),
392 		ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[1]),
393 		ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[2]),
394 		ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[3]),
395 		ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[4]),
396 		ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[5]),
397 		ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[6]),
398 		ntohs(((unsigned short *)&sa->__u6_addr.__u6_addr16)[7])
399 #endif
400 		) >= blen) {
401       Warn("sockaddr_inet6_info(): buffer too short");
402       buff[blen-1] = '\0';
403    }
404    return buff;
405 }
406 
407 
408 /* returns information that can be used for constructing an environment
409    variable describing the socket address.
410    if idx is 0, this function writes "ADDR" into namebuff and the IP address
411    into valuebuff, and returns 1 (which means that one more info is there).
412    if idx is 1, it writes "PORT" into namebuff and the port number into
413    valuebuff, and returns 0 (no more info)
414    namelen and valuelen contain the max. allowed length of output chars in the
415    respective buffer.
416    on error this function returns -1.
417 */
418 int
xiosetsockaddrenv_ip6(int idx,char * namebuff,size_t namelen,char * valuebuff,size_t valuelen,struct sockaddr_in6 * sa,int ipproto)419 xiosetsockaddrenv_ip6(int idx, char *namebuff, size_t namelen,
420 		      char *valuebuff, size_t valuelen,
421 		      struct sockaddr_in6 *sa, int ipproto) {
422    switch (idx) {
423    case 0:
424       strcpy(namebuff, "ADDR");
425       snprintf(valuebuff, valuelen, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
426 	       (sa->sin6_addr.s6_addr[0]<<8)+
427 	       sa->sin6_addr.s6_addr[1],
428 	       (sa->sin6_addr.s6_addr[2]<<8)+
429 	       sa->sin6_addr.s6_addr[3],
430 	       (sa->sin6_addr.s6_addr[4]<<8)+
431 	       sa->sin6_addr.s6_addr[5],
432 	       (sa->sin6_addr.s6_addr[6]<<8)+
433 	       sa->sin6_addr.s6_addr[7],
434 	       (sa->sin6_addr.s6_addr[8]<<8)+
435 	       sa->sin6_addr.s6_addr[9],
436 	       (sa->sin6_addr.s6_addr[10]<<8)+
437 	       sa->sin6_addr.s6_addr[11],
438 	       (sa->sin6_addr.s6_addr[12]<<8)+
439 	       sa->sin6_addr.s6_addr[13],
440 	       (sa->sin6_addr.s6_addr[14]<<8)+
441 	       sa->sin6_addr.s6_addr[15]);
442       switch (ipproto) {
443       case IPPROTO_TCP:
444       case IPPROTO_UDP:
445 #ifdef IPPROTO_SCTP
446       case IPPROTO_SCTP:
447 #endif
448 	 return 1;	/* there is port information to also be retrieved */
449       default:
450 	 return 0;	/* no port info coming */
451       }
452    case 1:
453       strcpy(namebuff, "PORT");
454       snprintf(valuebuff, valuelen, "%u", ntohs(sa->sin6_port));
455       return 0;
456    }
457    return -1;
458 }
459 
460 #endif /* WITH_IP6 */
461