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

How to get UDP destination address on incoming packets

3,357 views
Skip to first unread message
Message has been deleted

Michael Fuhr

unread,
Nov 14, 2003, 8:04:17 PM11/14/03
to
coleman...@aamatrix.com (Coleman Brumley) writes:

> Does anyone know how to get the destination address on incoming UDP
> packets?

This is covered in the bible: _UNIX Network Programming_, Volume 1,
by W. Richard Stevens; see Section 20.2 for an example of how to
do this with recvmsg(). Or google for something like "UDP destination
address recvmsg".

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/

Message has been deleted

Michael Fuhr

unread,
Nov 15, 2003, 1:04:49 PM11/15/03
to
coleman...@aamatrix.com (Coleman Brumley) writes:

> mf...@fuhr.org (Michael Fuhr) wrote in message news:<3fb57b91$1...@omega.dimensional.com>...


> > coleman...@aamatrix.com (Coleman Brumley) writes:
> >
> > > Does anyone know how to get the destination address on incoming UDP
> > > packets?
> >
> > This is covered in the bible: _UNIX Network Programming_, Volume 1,
> > by W. Richard Stevens; see Section 20.2 for an example of how to
> > do this with recvmsg(). Or google for something like "UDP destination
> > address recvmsg".
>

> I came accross information about using recvmsg with the IP_RECVDSTADDR
> socket option set.
>
> I read that IP_RECVDSTADDR (or IP_RECVIF) isn't supported by Linux. A
> grep of header files shows this constant doesn't exist.

On Linux I've used the IP_PKTINFO socket option. I usually write
code that must run on multiple platforms, so I use something like
this:

#if defined IP_RECVDSTADDR
# define DSTADDR_SOCKOPT IP_RECVDSTADDR
# define dstaddr(x) (CMSG_DATA(x))
#elif defined IP_PKTINFO
# define DSTADDR_SOCKOPT IP_PKTINFO
# define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr))
#endif

In the tests I've done, this code correctly returns the destination
IP address, whether unicast or broadcast.

Message has been deleted

Michael Fuhr

unread,
Nov 16, 2003, 1:13:21 PM11/16/03
to
coleman...@aamatrix.com (Coleman Brumley) writes:

> mf...@fuhr.org (Michael Fuhr) wrote in message news:<3fb66...@omega.dimensional.com>...


>
> > #if defined IP_RECVDSTADDR
> > # define DSTADDR_SOCKOPT IP_RECVDSTADDR
> > # define dstaddr(x) (CMSG_DATA(x))
> > #elif defined IP_PKTINFO
> > # define DSTADDR_SOCKOPT IP_PKTINFO
> > # define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr))
> > #endif

[snip]

> Would you be be able to expand upon this code a bit? Specifically,
> can you give me an example of using your dstaddr macro? What get's
> passes as x?

Here's a simple example:

for (cmsgptr = CMSG_FIRSTHDR(&msg);
cmsgptr != NULL;
cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {

if (cmsgptr->cmsg_level == IPPROTO_IP &&
cmsgptr->cmsg_type == DSTADDR_SOCKOPT) {

printf("destination: %s\n", inet_ntoa(*dstaddr(cmsgptr)));

Message has been deleted

Michael Fuhr

unread,
Nov 17, 2003, 12:51:14 AM11/17/03
to
coleman...@aamatrix.com (Coleman Brumley) writes:

> mf...@fuhr.org (Michael Fuhr) wrote in message news:<3fb7be41$1...@omega.dimensional.com>...


>
> > for (cmsgptr = CMSG_FIRSTHDR(&msg);
> > cmsgptr != NULL;
> > cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
> >
> > if (cmsgptr->cmsg_level == IPPROTO_IP &&
> > cmsgptr->cmsg_type == DSTADDR_SOCKOPT) {
> >
> > printf("destination: %s\n", inet_ntoa(*dstaddr(cmsgptr)));
> > }
> > }
>

> Ok, after looking at the man pages for cmsg and recvmsg, I can see how
> to get to this information via the msghdr structure. I'm guessing
> that I can just PEEK at the incoming mesg using recvmsg and then do
> the cmsg/dstaddr thing from above?

You could use MSG_PEEK if you don't want to read the data yet, or
you could read the data and do whatever you want with it.

> Is there anything special I have to do to the socket for this to work?
> I'm opening the socket using:
> sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
> ...
> bind(sock_fd, ...);
>
> I would also guess that I'll need to do setsockopt(DSTADDR_SOCKOPT)?

Yep, with a level of IPPROTO_IP.

Message has been deleted

Michael Fuhr

unread,
Nov 17, 2003, 10:29:51 PM11/17/03
to
coleman...@aamatrix.com (Coleman Brumley) writes:

> Ok, I'm at a loss. I did all this, and still nothing. I'm not sure
> if I'm setting up my socket correctly, though. Is there something I'm
> doing wrong here?

Below is a complete program that prints the received packet's
destination IP address. I just wrote it based on some other code
I have and haven't checked it thoroughly for subtle bugs, but in
simple tests it worked on both Linux and FreeBSD. Hopefully it
will answer any remaining questions you have.

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LISTEN_PORT 12345
#define BUFSIZE 1024

#if defined IP_RECVDSTADDR
# define DSTADDR_SOCKOPT IP_RECVDSTADDR

# define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in_addr)))


# define dstaddr(x) (CMSG_DATA(x))
#elif defined IP_PKTINFO
# define DSTADDR_SOCKOPT IP_PKTINFO

# define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in_pktinfo)))


# define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr))

#else
# error "can't determine socket option"
#endif

union control_data {
struct cmsghdr cmsg;
u_char data[DSTADDR_DATASIZE];
};

int
main(void)
{
int sock;
int sockopt;
struct sockaddr_in srvaddr;
struct sockaddr_in cliaddr;
struct msghdr msg;
union control_data cmsg;
struct cmsghdr *cmsgptr;
struct iovec iov[1];
ssize_t nbytes;
char buf[BUFSIZE];

setbuf(stdout, NULL);

sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
perror("socket");
exit(EXIT_FAILURE);
}

sockopt = 1;
if (setsockopt(sock, IPPROTO_IP, DSTADDR_SOCKOPT, &sockopt, sizeof sockopt) == -1) {
perror("setsockopt");
exit(EXIT_FAILURE);
}

memset(&srvaddr, 0, sizeof srvaddr);
srvaddr.sin_family = AF_INET;
srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);
srvaddr.sin_port = htons(LISTEN_PORT);

if (bind(sock, (struct sockaddr *)&srvaddr, sizeof srvaddr) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}

iov[0].iov_base = buf;
iov[0].iov_len = sizeof buf;

memset(&msg, 0, sizeof msg);
msg.msg_name = &cliaddr;
msg.msg_namelen = sizeof cliaddr;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_control = &cmsg;
msg.msg_controllen = sizeof cmsg;

for (;;) {
printf("recvmsg...");

nbytes = recvmsg(sock, &msg, 0);
if (nbytes == -1) {
perror("recvfrom");
exit(EXIT_FAILURE);
}

printf("%ld bytes ", (long)nbytes);
printf("from %s:%hu ", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));

for (cmsgptr = CMSG_FIRSTHDR(&msg);
cmsgptr != NULL;
cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {

if (cmsgptr->cmsg_level == IPPROTO_IP &&
cmsgptr->cmsg_type == DSTADDR_SOCKOPT) {

printf("to %s", inet_ntoa(*(struct in_addr *)dstaddr(cmsgptr)));
}
}

putchar('\n');
}

/*NOTREACHED*/
return EXIT_SUCCESS;

0 new messages