> 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/
> 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.
> 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)));
> 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.
> 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;