How to get UDP destination address on incoming packets

2729 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;

Reply all
Reply to author
Forward
0 new messages