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 */
5 /* this file contains the source for IP6 related functions */
7 #include "xiosysincludes.h"
12 #include "xio-ascii.h"
13 #include "xio-socket.h"
14 #include "xio-ip.h" /* xioresolve() */
20 static char *inet6addr_info(const struct in6_addr
*sa
, char *buff
, size_t blen
);
24 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
};
26 #ifdef IPV6_JOIN_GROUP
27 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
};
29 #ifdef MCAST_JOIN_SOURCE_GROUP
30 const struct optdesc opt_ipv6_join_source_group
= { "ipv6-join-source-group", "join-source-group", OPT_IPV6_JOIN_SOURCE_GROUP
, GROUP_SOCK_IP6
, PH_PASTSOCKET
, TYPE_GROUP_SOURCE_REQ
, OFUNC_SOCKOPT
, SOL_IPV6
, MCAST_JOIN_SOURCE_GROUP
};
33 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
};
35 #ifdef IPV6_RECVPKTINFO
36 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
};
39 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
};
42 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
};
45 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
};
48 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
};
50 #ifdef IPV6_RECVDSTOPTS
51 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
};
54 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
};
56 #ifdef IPV6_RECVHOPOPTS
57 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
};
59 #ifdef IPV6_FLOWINFO /* is in linux/in6.h */
60 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
};
63 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
};
65 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
};
66 #ifdef IPV6_RECVHOPLIMIT
67 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
};
70 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
};
73 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
};
75 #ifdef IPV6_RECVTCLASS
76 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
};
78 #ifdef IPV6_RECVPATHMTU
79 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
};
82 /* Returns canonical form of IPv6 address.
83 IPv6 address may be enclose in brackets.
84 Returns STAT_OK on success, STAT_NORETRY on failure. */
88 const int ai_flags
[2])
90 union sockaddr_union sockaddr
;
91 socklen_t sockaddrlen
= sizeof(sockaddr
);
94 char plainaddr
[INET6_ADDRSTRLEN
];
97 strncpy(plainaddr
, src
+1, INET6_ADDRSTRLEN
);
98 plainaddr
[INET6_ADDRSTRLEN
-1] = '\0';
99 if ((clos
= strchr(plainaddr
, ']')) != NULL
)
101 return xioip6_pton(plainaddr
, dst
, ai_flags
);
103 if (xioresolve(src
, NULL
, PF_INET6
, 0, 0, &sockaddr
, &sockaddrlen
,
108 *dst
= sockaddr
.ip6
.sin6_addr
;
112 int xioparsenetwork_ip6(
113 const char *rangename
,
114 struct xiorange
*range
,
115 const int ai_flags
[2])
117 char *delimpos
; /* absolute address of delimiter */
118 size_t delimind
; /* index of delimiter in string */
119 unsigned int bits
; /* netmask bits */
122 union sockaddr_union sockaddr
;
123 socklen_t sockaddrlen
= sizeof(sockaddr
);
124 union xioin6_u
*rangeaddr
= (union xioin6_u
*)&range
->netaddr
.ip6
.sin6_addr
;
125 union xioin6_u
*rangemask
= (union xioin6_u
*)&range
->netmask
.ip6
.sin6_addr
;
126 union xioin6_u
*nameaddr
= (union xioin6_u
*)&sockaddr
.ip6
.sin6_addr
;
128 if ((delimpos
= strchr(rangename
, '/')) == NULL
) {
129 Error1("xioparsenetwork_ip6(\"%s\",,): missing mask bits delimiter '/'",
133 delimind
= delimpos
- rangename
;
134 if (rangename
[0] != '[' || rangename
[delimind
-1] != ']') {
135 Error1("missing brackets for IPv6 range definition \"%s\"",
140 if ((baseaddr
= strndup(rangename
+1,delimind
-2)) == NULL
) {
141 Error1("strdup(\"%s\"): out of memory", rangename
+1);
144 baseaddr
[delimind
-2] = '\0';
145 if (xioresolve(baseaddr
, NULL
, PF_INET6
, 0, 0, &sockaddr
, &sockaddrlen
,
150 rangeaddr
->u6_addr32
[0] = nameaddr
->u6_addr32
[0];
151 rangeaddr
->u6_addr32
[1] = nameaddr
->u6_addr32
[1];
152 rangeaddr
->u6_addr32
[2] = nameaddr
->u6_addr32
[2];
153 rangeaddr
->u6_addr32
[3] = nameaddr
->u6_addr32
[3];
154 bits
= strtoul(delimpos
+1, &endptr
, 10);
155 if (! ((*(delimpos
+1) != '\0') && (*endptr
== '\0'))) {
156 Error1("not a valid netmask in \"%s\"", rangename
);
157 bits
= 128; /* most secure selection */
158 } else if (bits
> 128) {
159 Error1("netmask \"%s\" is too large", rangename
);
163 /* I am starting to dislike C...uint32_t << 32 is undefined... */
165 rangemask
->u6_addr32
[0] = 0;
166 rangemask
->u6_addr32
[1] = 0;
167 rangemask
->u6_addr32
[2] = 0;
168 rangemask
->u6_addr32
[3] = 0;
169 } else if (bits
<= 32) {
170 rangemask
->u6_addr32
[0] = htonl(0xffffffff << (32-bits
));
171 rangemask
->u6_addr32
[1] = 0;
172 rangemask
->u6_addr32
[2] = 0;
173 rangemask
->u6_addr32
[3] = 0;
174 } else if (bits
<= 64) {
175 rangemask
->u6_addr32
[0] = 0xffffffff;
176 rangemask
->u6_addr32
[1] = htonl(0xffffffff << (64-bits
));
177 rangemask
->u6_addr32
[2] = 0;
178 rangemask
->u6_addr32
[3] = 0;
179 } else if (bits
<= 96) {
180 rangemask
->u6_addr32
[0] = 0xffffffff;
181 rangemask
->u6_addr32
[1] = 0xffffffff;
182 rangemask
->u6_addr32
[2] = htonl(0xffffffff << (96-bits
));
183 rangemask
->u6_addr32
[3] = 0;
185 rangemask
->u6_addr32
[0] = 0xffffffff;
186 rangemask
->u6_addr32
[1] = 0xffffffff;
187 rangemask
->u6_addr32
[2] = 0xffffffff;
188 rangemask
->u6_addr32
[3] = htonl(0xffffffff << (128-bits
));
193 int xiorange_ip6andmask(struct xiorange
*range
) {
196 range
->addr
.s6_addr32
[0] &= range
->mask
.s6_addr32
[0];
197 range
->addr
.s6_addr32
[1] &= range
->mask
.s6_addr32
[1];
198 range
->addr
.s6_addr32
[2] &= range
->mask
.s6_addr32
[2];
199 range
->addr
.s6_addr32
[3] &= range
->mask
.s6_addr32
[3];
201 for (i
= 0; i
< 16; ++i
) {
202 range
->netaddr
.ip6
.sin6_addr
.s6_addr
[i
] &=
203 range
->netmask
.ip6
.sin6_addr
.s6_addr
[i
];
209 /* check if peer address is within permitted range.
210 return >= 0 if so. */
211 int xiocheckrange_ip6(struct sockaddr_in6
*pa
, struct xiorange
*range
) {
212 union xioin6_u masked
;
215 union xioin6_u
*rangeaddr
= (union xioin6_u
*)&range
->netaddr
.ip6
.sin6_addr
;
216 union xioin6_u
*rangemask
= (union xioin6_u
*)&range
->netmask
.ip6
.sin6_addr
;
218 Debug16("permitted client subnet: [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]:[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
219 htons(rangeaddr
->u6_addr16
[0]), htons(rangeaddr
->u6_addr16
[1]),
220 htons(rangeaddr
->u6_addr16
[2]), htons(rangeaddr
->u6_addr16
[3]),
221 htons(rangeaddr
->u6_addr16
[4]), htons(rangeaddr
->u6_addr16
[5]),
222 htons(rangeaddr
->u6_addr16
[6]), htons(rangeaddr
->u6_addr16
[7]),
223 htons(rangemask
->u6_addr16
[0]), htons(rangemask
->u6_addr16
[1]),
224 htons(rangemask
->u6_addr16
[2]), htons(rangemask
->u6_addr16
[3]),
225 htons(rangemask
->u6_addr16
[4]), htons(rangemask
->u6_addr16
[5]),
226 htons(rangemask
->u6_addr16
[6]), htons(rangemask
->u6_addr16
[7]));
227 Debug1("client address is %s",
228 sockaddr_inet6_info(pa
, peername
, sizeof(peername
)));
230 for (i
= 0; i
< 4; ++i
) {
231 masked
.u6_addr32
[i
] = ((union xioin6_u
*)&pa
->sin6_addr
.s6_addr
[0])->u6_addr32
[i
] & rangemask
->u6_addr32
[i
];
233 Debug8("masked address is [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
234 htons(masked
.u6_addr16
[0]), htons(masked
.u6_addr16
[1]),
235 htons(masked
.u6_addr16
[2]), htons(masked
.u6_addr16
[3]),
236 htons(masked
.u6_addr16
[4]), htons(masked
.u6_addr16
[5]),
237 htons(masked
.u6_addr16
[6]), htons(masked
.u6_addr16
[7]));
239 if (masked
.u6_addr32
[0] != rangeaddr
->u6_addr32
[0] ||
240 masked
.u6_addr32
[1] != rangeaddr
->u6_addr32
[1] ||
241 masked
.u6_addr32
[2] != rangeaddr
->u6_addr32
[2] ||
242 masked
.u6_addr32
[3] != rangeaddr
->u6_addr32
[3]) {
243 Debug1("client address %s is not permitted", peername
);
250 #if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
251 /* provides info about the ancillary message:
252 converts the ancillary message in *cmsg into a form useable for further
253 processing. knows the specifics of common message types.
254 returns the number of resulting syntax elements in *num
255 returns a sequence of \0 terminated type strings in *typbuff
256 returns a sequence of \0 terminated name strings in *nambuff
257 returns a sequence of \0 terminated value strings in *valbuff
258 the respective len parameters specify the available space in the buffers
259 returns STAT_OK on success
261 int xiolog_ancillary_ip6(
263 struct cmsghdr
*cmsg
,
265 char *typbuff
, int typlen
,
266 char *nambuff
, int namlen
,
267 char *envbuff
, int envlen
,
268 char *valbuff
, int vallen
)
270 char scratch1
[42]; /* can hold an IPv6 address in ASCII */
274 *num
= 1; /* good for most message types */
275 msglen
= cmsg
->cmsg_len
-((char *)CMSG_DATA(cmsg
)-(char *)cmsg
);
277 switch (cmsg
->cmsg_type
) {
278 #if defined(IPV6_PKTINFO) && HAVE_STRUCT_IN6_PKTINFO
280 struct in6_pktinfo
*pktinfo
= (struct in6_pktinfo
*)CMSG_DATA(cmsg
);
282 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_PKTINFO", typlen
-1);
283 snprintf(nambuff
, namlen
, "%s%c%s", "dstaddr", '\0', "if");
284 snprintf(envbuff
, envlen
, "%s%c%s", "IPV6_DSTADDR", '\0', "IPV6_IF");
285 snprintf(valbuff
, vallen
, "%s%c%s",
286 inet6addr_info(&pktinfo
->ipi6_addr
, scratch1
, sizeof(scratch1
)),
287 '\0', xiogetifname(pktinfo
->ipi6_ifindex
, scratch2
, -1));
290 #endif /* defined(IPV6_PKTINFO) && HAVE_STRUCT_IN6_PKTINFO */
293 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_HOPLIMIT", typlen
-1);
294 nambuff
[0] = '\0'; strncat(nambuff
, "hoplimit", namlen
-1);
296 int *intp
= (int *)CMSG_DATA(cmsg
);
297 snprintf(valbuff
, vallen
, "%d", *intp
);
300 #endif /* defined(IPV6_HOPLIMIT) */
303 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_RTHDR", typlen
-1);
304 nambuff
[0] = '\0'; strncat(nambuff
, "rthdr", namlen
-1);
305 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
307 #endif /* defined(IPV6_RTHDR) */
310 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_AUTHHDR", typlen
-1);
311 nambuff
[0] = '\0'; strncat(nambuff
, "authhdr", namlen
-1);
312 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
317 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_DSTOPTS", typlen
-1);
318 nambuff
[0] = '\0'; strncat(nambuff
, "dstopts", namlen
-1);
319 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
321 #endif /* defined(IPV6_DSTOPTS) */
324 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_HOPOPTS", typlen
-1);
325 nambuff
[0] = '\0'; strncat(nambuff
, "hopopts", namlen
-1);
326 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
328 #endif /* defined(IPV6_HOPOPTS) */
331 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_FLOWINFO", typlen
-1);
332 nambuff
[0] = '\0'; strncat(nambuff
, "flowinfo", namlen
-1);
333 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
339 typbuff
[0] = '\0'; strncat(typbuff
, "IPV6_TCLASS", typlen
-1);
340 nambuff
[0] = '\0'; strncat(nambuff
, "tclass", namlen
-1);
341 u
= ntohl(*(unsigned int *)CMSG_DATA(cmsg
));
342 xiodump((const unsigned char *)&u
, msglen
, valbuff
, vallen
, 0);
347 snprintf(typbuff
, typlen
, "IPV6.%u", cmsg
->cmsg_type
);
348 nambuff
[0] = '\0'; strncat(nambuff
, "data", namlen
-1);
349 xiodump(CMSG_DATA(cmsg
), msglen
, valbuff
, vallen
, 0);
354 #endif /* defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) */
357 /* convert the IP6 socket address to human readable form. buff should be at
358 least 50 chars long. output includes the port number */
359 static char *inet6addr_info(const struct in6_addr
*sa
, char *buff
, size_t blen
) {
360 if (xio_snprintf(buff
, blen
, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
361 #if HAVE_IP6_SOCKADDR==0
362 (sa
->s6_addr
[0]<<8)+sa
->s6_addr
[1],
363 (sa
->s6_addr
[2]<<8)+sa
->s6_addr
[3],
364 (sa
->s6_addr
[4]<<8)+sa
->s6_addr
[5],
365 (sa
->s6_addr
[6]<<8)+sa
->s6_addr
[7],
366 (sa
->s6_addr
[8]<<8)+sa
->s6_addr
[9],
367 (sa
->s6_addr
[10]<<8)+sa
->s6_addr
[11],
368 (sa
->s6_addr
[12]<<8)+sa
->s6_addr
[13],
369 (sa
->s6_addr
[14]<<8)+sa
->s6_addr
[15]
370 #elif HAVE_IP6_SOCKADDR==1
371 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[0]),
372 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[1]),
373 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[2]),
374 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[3]),
375 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[4]),
376 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[5]),
377 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[6]),
378 ntohs(((unsigned short *)&sa
->u6_addr
.u6_addr16
)[7])
379 #elif HAVE_IP6_SOCKADDR==2
380 ntohs(((unsigned short *)&sa
->u6_addr16
)[0]),
381 ntohs(((unsigned short *)&sa
->u6_addr16
)[1]),
382 ntohs(((unsigned short *)&sa
->u6_addr16
)[2]),
383 ntohs(((unsigned short *)&sa
->u6_addr16
)[3]),
384 ntohs(((unsigned short *)&sa
->u6_addr16
)[4]),
385 ntohs(((unsigned short *)&sa
->u6_addr16
)[5]),
386 ntohs(((unsigned short *)&sa
->u6_addr16
)[6]),
387 ntohs(((unsigned short *)&sa
->u6_addr16
)[7])
388 #elif HAVE_IP6_SOCKADDR==3
389 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[0]),
390 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[1]),
391 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[2]),
392 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[3]),
393 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[4]),
394 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[5]),
395 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[6]),
396 ntohs(((unsigned short *)&sa
->in6_u
.u6_addr16
)[7])
397 #elif HAVE_IP6_SOCKADDR==4
398 (sa
->_S6_un
._S6_u8
[0]<<8)|(sa
->_S6_un
._S6_u8
[1]&0xff),
399 (sa
->_S6_un
._S6_u8
[2]<<8)|(sa
->_S6_un
._S6_u8
[3]&0xff),
400 (sa
->_S6_un
._S6_u8
[4]<<8)|(sa
->_S6_un
._S6_u8
[5]&0xff),
401 (sa
->_S6_un
._S6_u8
[6]<<8)|(sa
->_S6_un
._S6_u8
[7]&0xff),
402 (sa
->_S6_un
._S6_u8
[8]<<8)|(sa
->_S6_un
._S6_u8
[9]&0xff),
403 (sa
->_S6_un
._S6_u8
[10]<<8)|(sa
->_S6_un
._S6_u8
[11]&0xff),
404 (sa
->_S6_un
._S6_u8
[12]<<8)|(sa
->_S6_un
._S6_u8
[13]&0xff),
405 (sa
->_S6_un
._S6_u8
[14]<<8)|(sa
->_S6_un
._S6_u8
[15]&0xff)
406 #elif HAVE_IP6_SOCKADDR==5
407 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[0]),
408 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[1]),
409 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[2]),
410 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[3]),
411 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[4]),
412 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[5]),
413 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[6]),
414 ntohs(((unsigned short *)&sa
->__u6_addr
.__u6_addr16
)[7])
417 Warn("sockaddr_inet6_info(): buffer too short");
424 /* returns information that can be used for constructing an environment
425 variable describing the socket address.
426 if idx is 0, this function writes "ADDR" into namebuff and the IP address
427 into valuebuff, and returns 1 (which means that one more info is there).
428 if idx is 1, it writes "PORT" into namebuff and the port number into
429 valuebuff, and returns 0 (no more info)
430 namelen and valuelen contain the max. allowed length of output chars in the
432 on error this function returns -1.
435 xiosetsockaddrenv_ip6(int idx
, char *namebuff
, size_t namelen
,
436 char *valuebuff
, size_t valuelen
,
437 struct sockaddr_in6
*sa
, int ipproto
) {
440 strcpy(namebuff
, "ADDR");
441 snprintf(valuebuff
, valuelen
, "[%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]",
442 (sa
->sin6_addr
.s6_addr
[0]<<8)+
443 sa
->sin6_addr
.s6_addr
[1],
444 (sa
->sin6_addr
.s6_addr
[2]<<8)+
445 sa
->sin6_addr
.s6_addr
[3],
446 (sa
->sin6_addr
.s6_addr
[4]<<8)+
447 sa
->sin6_addr
.s6_addr
[5],
448 (sa
->sin6_addr
.s6_addr
[6]<<8)+
449 sa
->sin6_addr
.s6_addr
[7],
450 (sa
->sin6_addr
.s6_addr
[8]<<8)+
451 sa
->sin6_addr
.s6_addr
[9],
452 (sa
->sin6_addr
.s6_addr
[10]<<8)+
453 sa
->sin6_addr
.s6_addr
[11],
454 (sa
->sin6_addr
.s6_addr
[12]<<8)+
455 sa
->sin6_addr
.s6_addr
[13],
456 (sa
->sin6_addr
.s6_addr
[14]<<8)+
457 sa
->sin6_addr
.s6_addr
[15]);
464 return 1; /* there is port information to also be retrieved */
466 return 0; /* no port info coming */
469 strcpy(namebuff
, "PORT");
470 snprintf(valuebuff
, valuelen
, "%u", ntohs(sa
->sin6_port
));
477 #if defined(HAVE_STRUCT_IPV6_MREQ)
478 int xioapply_ipv6_join_group(
482 struct ipv6_mreq ip6_mreq
= {{{{0}}}};
483 union sockaddr_union sockaddr1
;
484 socklen_t socklen1
= sizeof(sockaddr1
.ip6
);
487 /* Always two parameters */
488 /* First parameter is multicast address */
490 xioresolve(opt
->value
.u_string
/*multiaddr*/, NULL
,
491 sfd
->para
.socket
.la
.soa
.sa_family
,
492 SOCK_DGRAM
, IPPROTO_IP
,
493 &sockaddr1
, &socklen1
,
494 sfd
->para
.socket
.ip
.ai_flags
))
498 ip6_mreq
.ipv6mr_multiaddr
= sockaddr1
.ip6
.sin6_addr
;
499 if (ifindex(opt
->value2
.u_string
/*param2*/,
500 &ip6_mreq
.ipv6mr_interface
, -1)
502 Error1("interface \"%s\" not found",
503 opt
->value2
.u_string
/*param2*/);
504 ip6_mreq
.ipv6mr_interface
= htonl(0);
507 if (Setsockopt(sfd
->fd
, opt
->desc
->major
, opt
->desc
->minor
,
508 &ip6_mreq
, sizeof(ip6_mreq
)) < 0) {
509 Error6("setsockopt(%d, %d, %d, {...,0x%08x}, "F_Zu
"): %s",
510 sfd
->fd
, opt
->desc
->major
, opt
->desc
->minor
,
511 ip6_mreq
.ipv6mr_interface
,
514 opt
->desc
= ODESC_ERROR
;
519 #endif /* defined(HAVE_STRUCT_IPV6_MREQ) */
521 #if HAVE_STRUCT_GROUP_SOURCE_REQ
522 int xiotype_ip6_join_source_group(
523 char *token
, const struct optname
*ent
, struct opt
*opt
)
525 /* We do not resolve the addresses here because we do not yet know
526 if we are coping with an IPv4 or IPv6 socat address */
527 const char *ends
[] = { ":", NULL
};
528 const char *nests
[] = { "[","]", NULL
};
529 char buff
[512], *buffp
=buff
; size_t bufspc
= sizeof(buff
)-1;
533 /* Parse first IP address (mcast group), expect ':' */
535 nestlex((const char **)&tokp
, &buffp
, &bufspc
,
536 ends
, NULL
, NULL
, nests
,
539 Error1("option too long: \"%s\"", token
);
541 } else if (parsres
> 0) {
542 Error1("syntax error in \"%s\"", token
);
546 Error1("syntax in option %s: missing ':'", token
);
549 if ((opt
->value
.u_string
/*mcaddr*/ = strdup(buff
)) == NULL
) {
551 Error1("strdup(\"%s\"): out of memory", buff
);
557 /* Parse interface name/index, expect ':' or '\0'' */
560 nestlex((const char **)&tokp
, &buffp
, &bufspc
,
561 ends
, NULL
, NULL
, nests
,
564 Error1("option too long: \"%s\"", token
);
566 } else if (parsres
> 0) {
567 Error1("syntax error in \"%s\"", token
);
571 Error1("syntax in option %s: missing ':'", token
);
574 if ((opt
->value2
.u_string
/*ifindex*/ = Malloc(IF_NAMESIZE
)) == NULL
) {
576 free(opt
->value
.u_string
);
580 strncpy(opt
->value2
.u_string
/*ifindex*/, buff
, IF_NAMESIZE
);
583 /* Parse second IP address (source address), expect ':' or '\0'' */
586 nestlex((const char **)&tokp
, &buffp
, &bufspc
,
587 ends
, NULL
, NULL
, nests
,
590 Error1("option too long: \"%s\"", token
);
592 } else if (parsres
> 0) {
593 Error1("syntax error in \"%s\"", token
);
597 Error1("syntax in option %s: trailing cruft", token
);
600 if ((opt
->value3
.u_string
/*srcaddr*/ = strdup(buff
)) == NULL
) {
602 Error1("strdup(\"%s\"): out of memory", buff
);
603 free(opt
->value
.u_string
);
608 Info4("setting option \"%s\" to {\"%s\",\"%s\",\"%s\"}",
610 opt
->value
.u_string
/*mcaddr*/,
611 opt
->value2
.u_string
/*ifindex*/,
612 opt
->value3
.u_string
/*srcaddr*/);
614 if (!xioparms
.experimental
) {
615 Warn1("option %s is experimental", opt
->desc
->defname
);
621 int xioapply_ip6_join_source_group(struct single
*sfd
, struct opt
*opt
) {
622 struct group_source_req ip6_gsr
= {0};
623 union sockaddr_union sockaddr1
;
624 socklen_t socklen1
= sizeof(sockaddr1
.ip6
);
625 union sockaddr_union sockaddr2
;
626 socklen_t socklen2
= sizeof(sockaddr2
.ip6
);
629 /* First parameter is always multicast address */
631 xioresolve(opt
->value
.u_string
/*mcaddr*/, NULL
,
632 sfd
->para
.socket
.la
.soa
.sa_family
,
633 SOCK_DGRAM
, IPPROTO_IP
, &sockaddr1
, &socklen1
,
634 sfd
->para
.socket
.ip
.ai_flags
))
638 memcpy(&ip6_gsr
.gsr_group
, &sockaddr1
.ip6
, socklen1
);
639 /* Second parameter is interface name/index */
640 if (ifindex(opt
->value2
.u_string
/*ifindex*/,
641 &ip6_gsr
.gsr_interface
, -1)
643 Error1("interface \"%s\" not found",
644 opt
->value
.u_string
/*ifindex*/);
645 ip6_gsr
.gsr_interface
= 0;
647 /* Third parameter is source address */
649 xioresolve(opt
->value3
.u_string
/*srcaddr*/, NULL
,
650 sfd
->para
.socket
.la
.soa
.sa_family
,
651 SOCK_DGRAM
, IPPROTO_IP
, &sockaddr2
, &socklen2
,
652 sfd
->para
.socket
.ip
.ai_flags
))
656 memcpy(&ip6_gsr
.gsr_source
, &sockaddr2
.ip6
, socklen2
);
657 if (Setsockopt(sfd
->fd
, opt
->desc
->major
, opt
->desc
->minor
,
658 &ip6_gsr
, sizeof(ip6_gsr
)) < 0) {
659 Error6("setsockopt(%d, %d, %d, {%d,...}, "F_Zu
"): %s",
660 sfd
->fd
, opt
->desc
->major
, opt
->desc
->minor
,
661 ip6_gsr
.gsr_interface
,
664 opt
->desc
= ODESC_ERROR
;
669 #endif /* HAVE_STRUCT_GROUP_SOURCE_REQ */
671 #endif /* WITH_IP6 */