Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

sendmsg() with ancillary data doesn't work properly

107 views
Skip to first unread message

Jiri Klimes

unread,
Nov 30, 2006, 10:16:38 AM11/30/06
to
Hello all,

I have a UDP socket;
sock = socket(PF_INET6, SOCK_DGRAM, 0);
and then to bound to an address.

I want to use this socket for sending a message, but with different address
than is bound to it.
I am using sendmsg() with ancillary data to it. The message is sent out
correctly, but with WRONG source IP.

The IP bound to the socket was IPv6 ::
I am trying to use an IPv4 in ancillary data for source address in
sendmsg(). Maybe this i not supported??
Or is something else wrong?

I would be very helpful to receive some advice.
Thanks,
Jiri Klimes


Tim Bradshaw

unread,
Nov 30, 2006, 10:49:09 AM11/30/06
to
Jiri Klimes wrote:

> The IP bound to the socket was IPv6 ::
> I am trying to use an IPv4 in ancillary data for source address in
> sendmsg(). Maybe this i not supported??
> Or is something else wrong?

It seems to me very, very unlikely that you can send data out from an
IPv4 address on a socket which is using IPv6.

Jiri Klimes

unread,
Nov 30, 2006, 11:02:23 AM11/30/06
to
Tim Bradshaw wrote:

It's ok. IPv6 sockets can be used for sending IPv4 packet using so called
IPv6-mapped IPv4 adresses (textualy e.g ::ffff:1.2.3.4). See RFC 3493 chap.
3.7.

But my problem is really taht sendmsg() with source addr as ancillary data
doesn't use the provided source address.
Here is wrapper function that I use:

/* this function is similar to standard sendto(), but it has an extra
parameter (last) to specify source address for the operation. It will be
set as ancillary data to call of sendto() function */
ssize_t xsendto(int s, void *buf, size_t len, int flags,
struct sockaddr *to, socklen_t tolen, struct in6_pktinfo *pktinfo)
{
struct msghdr msg;
char pktbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
struct cmsghdr *cmptr;
struct iovec iov[1];
ssize_t n;
struct in6_pktinfo *pktinfo_tmp;

msg.msg_name = to;
msg.msg_namelen = tolen;
iov[0].iov_base = buf;
iov[0].iov_len = len;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_flags = 0;

msg.msg_control = pktbuf;
msg.msg_controllen = sizeof(pktbuf);
cmptr = CMSG_FIRSTHDR(&msg);
cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
cmptr->cmsg_level = IPPROTO_IPV6;
cmptr->cmsg_type = IPV6_PKTINFO;
pktinfo_tmp = (struct in6_pktinfo *) CMSG_DATA(cmptr);
*pktinfo_tmp = *pktinfo;

/* call sendmsg() to send data from specified source address */
if ((n=sendmsg(s, &msg, flags)) < 0)
{
perror("sendmsg() failed");
return n;
}
return n;
}

Is something wrong with it?

Tim Bradshaw

unread,
Nov 30, 2006, 12:32:44 PM11/30/06
to
Jiri Klimes wrote:

>
> It's ok. IPv6 sockets can be used for sending IPv4 packet using so called
> IPv6-mapped IPv4 adresses (textualy e.g ::ffff:1.2.3.4). See RFC 3493 chap.
> 3.7.
>

Oh cool, I didn't know you could do that. (No comment on the code,
sorry).

--tim

Casper H.S. Dik

unread,
Nov 30, 2006, 12:41:43 PM11/30/06
to
Jiri Klimes <jiri....@siemens.com> writes:

> char pktbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];

As a minimum, you need to make sure that this variable is
aligned on the appropriate boundary or bad things happen.

Casper

James Carlson

unread,
Nov 30, 2006, 3:30:22 PM11/30/06
to
Jiri Klimes <jiri....@siemens.com> writes:
> It's ok. IPv6 sockets can be used for sending IPv4 packet using so called
> IPv6-mapped IPv4 adresses (textualy e.g ::ffff:1.2.3.4). See RFC 3493 chap.
> 3.7.

That's true. That part does work.

However, ancillary data on IPv6 sockets does *not* accept or work with
any of the IPv4 mapped addresses. They work with bind() and connect()
alone. There are no plans to make ancillary data work with
IPv4-mapped addresses on IPv6 sockets.

See CRs 6423782, 6423787, 6415277, 6415268, 6415261.

The recommended behavior for applications that must support IPv4 and
IPv6 and use ancillary data is to open two sockets -- one for v4 and
the other for v6.

Unfortunately, the RFE for IPv4 IP_PKTINFO isn't done yet.

--
James Carlson 42.703N 71.076W <carl...@workingcode.com>

Jiri Klimes

unread,
Dec 1, 2006, 4:52:44 AM12/1/06
to
James Carlson wrote:

Firstly thanks for your reply.



> However, ancillary data on IPv6 sockets does *not* accept or work with
> any of the IPv4 mapped addresses. They work with bind() and connect()
> alone. There are no plans to make ancillary data work with
> IPv4-mapped addresses on IPv6 sockets.
>
> See CRs 6423782, 6423787, 6415277, 6415268, 6415261.
>

OK, I see that mapped addresses are frowned at, but still I like then as
they are elegant and easy to use.



> The recommended behavior for applications that must support IPv4 and
> IPv6 and use ancillary data is to open two sockets -- one for v4 and
> the other for v6.
>
> Unfortunately, the RFE for IPv4 IP_PKTINFO isn't done yet.
>

It's bad news, because for my case it would be most straighworward.

But more question:
In a discussion I found post of Blaise Sanouillet saying:
<quote>
I'll confess that I really like IPv4-mapped addresses, precisely because
they solve the UDP source address issue transparently, without having to
mess about with ancillary data. (The __sin6_src_id field in sockaddr_in6
that makes this work is only present on Solaris, however.) So you wouldn't
have to use IPV6_PKTINFO to specify the source address with IPv4-mapped
addresses anyway. Save the ::ffff :-)
</quote>

So, is it really possible to specify source address using __sin6_src_id
field of sockaddr_in6 struct?
If yes, it would help me.
But which structure is that. sockaddr_in6 of destination address in sendto?
Or some other?

However I've tried, but no success.

Jiri Klimes

unread,
Dec 1, 2006, 4:54:12 AM12/1/06
to
Casper H.S. Dik wrote:

Which boundary do you mean? some example?

Jirka

Casper H.S. Dik

unread,
Dec 1, 2006, 6:08:08 AM12/1/06
to
Jiri Klimes <jiri....@siemens.com> writes:

>Casper H.S. Dik wrote:

It needs to be aligned on a 4 byte boundary; there is no guarantee
that char arrays on the stack are aligned in that way.

Casper
--
Expressed in this posting are my opinions. They are in no way related
to opinions held by my employer, Sun Microsystems.
Statements on Sun products included here are not gospel and may
be fiction rather than truth.

Jiri Klimes

unread,
Dec 1, 2006, 7:17:27 AM12/1/06
to
Jiri Klimes wrote:

> So, is it really possible to specify source address using __sin6_src_id
> field of sockaddr_in6 struct?
> If yes, it would help me.
> But which structure is that. sockaddr_in6 of destination address in
> sendto? Or some other?
>
> However I've tried, but no success.

I did it in a bad way. (quicker in writting than thinking :))

Now I can see that an index to a table is neccessary.
As I've understood it is filled using recvfrom() and then transparently
passed to sendto() with sokaddr_in6 structure.
But, in my case I need to use it in sendto/sendmsg without previous
recvfrom().
Am I able to do it? E.g. by filling the table by some function
(ip_srcid_insert() ??) and than use the index to populate __sin6_src_id ?


James Carlson

unread,
Dec 1, 2006, 6:09:01 PM12/1/06
to
Jiri Klimes <jiri....@siemens.com> writes:
> OK, I see that mapped addresses are frowned at, but still I like then as
> they are elegant and easy to use.

I agree, but Erik Nordmark does not.

The problem is two-fold:

- The v4 portion of the implementation does not know how to deal
with the pktinfo bits at all. It's just not there, so it doesn't
matter _what_ the v6 side supports. This is the subject of CR
4773220, which is being worked on now for Solaris Nevada.

- Making the interfaces nice and orthogonal is extra work (perhaps
substantial extra work; I'm not sure), and Erik believes that
making the ancillary data interfaces work with mapped addresses
should not be done because those addresses are just a migration
hack and not really the right way to do things. There's no reason
to extend them.

When we talked about this issue, we reached an impass: I wanted to see
the engineer doing this work make mapped addresses work the same way
for IPV6_PKTINFO as for IP_PKTINFO on regular v4. He wanted to keep
them separate to simplify the implementation and do only IP_PKTINFO
because nobody should need that mapped address support anymore. We
agreed to have RFEs filed to update the documentation so that users
wouldn't wander directly into this area ... as you have.

The best suggestion I can make right now is to join the
networking-discuss mailing list on opensolaris.org (if you have not
already done so), and make your argument there. Maybe you can sway
the thinking here.

> It's bad news, because for my case it would be most straighworward.

Indeed. I need IP_PKTINFO as well. But it's coming soon.

> So, is it really possible to specify source address using __sin6_src_id
> field of sockaddr_in6 struct?

Only the v6 source, and only indirectly. For recv*(), it's the
ifIndex number of the interface on which the UDP message originally
arrived, and it'll select that same interface on send*(). It's also
an internal implementation detail, subject to change at any time
without notice. Applications must not rely on it.

I also consider to be a bit of an ugly hack, because it doesn't
necessarily work right when you have a lot of addresses. Using
IP_PKTINFO is a *MUCH* better answer to the RFC 1123 section 2.3
requirements.

> If yes, it would help me.

No, it won't.

> But which structure is that. sockaddr_in6 of destination address in sendto?
> Or some other?

Yes. But it won't help here.

0 new messages