IP option IP_RECVTTL question
Hi, I wrote a DNS server and I'm collecting TTL information from the remote nameservers that query my daemon. Everything works well, when I view the logs I see: Feb 3 10:43:48 uranus wildcarddnsd[5705]: request on descriptor 14 interface em0 from XXX.XXX.XXX.XX (ttl=113, region=255) for centroid.eu. type=A(1) class=1, answering centroid.eu. Where the TTL is logged as 113 in this example. But occasionally I get this on OpenBSD/i386 and /amd64... Feb 3 10:45:01 uranus wildcarddnsd[5705]: request on descriptor 14 interface em0 from XXX.XX.XX.XX (ttl=27263547, region=255) for goldflipper.net. type=A(1) class=1, answering goldflipper.net. Where the TTL is a bad value. I think I'm using the code the right way after the manpage ip(4): If the IP_RECVTTL option is enabled on a SOCK_DGRAM or SOCK_RAW socket, the recvmsg(2) call will return the TTL of the received datagram. The msg_control field in the msghdr structure points to a buffer that contains a cmsghdr structure followed by the TTL value. The cmsghdr fields have the following values: cmsg_len = CMSG_LEN(sizeof(struct in_addr)) cmsg_level = IPPROTO_IP cmsg_type = IP_RECVTTL And if I'm not mistaken the size of struct in_addr is 4. Since sourceforge is down I can't refer you to the webcvs but they still offer the files for download if you want to take a peak at the source code that'd be great! http://sourceforge.net/projects/wildcarddns/files/ Here are some snippets from my source code perhaps you can spot what I'm doing wrong? ... if (setsockopt(udp[i], IPPROTO_IP, IP_RECVTTL, on, sizeof(on)) 0) { ... #ifdef __FreeBSD__ u_char *ttlptr; #elif __OpenBSD__ struct in_addr *ttlptr; #else int *ttlptr; #endif u_int32_t received_ttl; ... #if __FreeBSD__ ttlptr = (u_char *) CMSG_DATA(cmsg); received_ttl = (u_int)*ttlptr; #elif __OpenBSD__ ttlptr = (struct in_addr *) CMSG_DATA(cmsg); memcpy(received_ttl, ttlptr, sizeof(u_int32_t)); #else ttlptr = (int *) CMSG_DATA(cmsg); received_ttl = (u_int)*ttlptr; #endif ... syslog(LOG_INFO, request on descriptor %u interface \%s\ from %s (ttl=%u, region=%d) for \%s\ type=%s class=%u, answering \%s\, so, ident[i], address, received_ttl, aregion, question-converted_name, get_dns_type(ntohs(question-hdr-qtype)), ntohs(question-hdr-qclass), replystring); ... Unfortunately this #define hell is a mess but it's the only way to get this portable among BSD's and Linux. I'm hoping someone can tell where I'm going wrong with this and why it's right sometimes and wrong the occasional time. Regards, -peter
Re: IP option IP_RECVTTL question
On Thu, Feb 03, 2011 at 12:24:37PM +0100, Peter J. Philipp wrote: Hi, I wrote a DNS server and I'm collecting TTL information from the remote nameservers that query my daemon. Everything works well, when I view the logs I see: Feb 3 10:43:48 uranus wildcarddnsd[5705]: request on descriptor 14 interface em0 from XXX.XXX.XXX.XX (ttl=113, region=255) for centroid.eu. type=A(1) class=1, answering centroid.eu. Where the TTL is logged as 113 in this example. But occasionally I get this on OpenBSD/i386 and /amd64... Feb 3 10:45:01 uranus wildcarddnsd[5705]: request on descriptor 14 interface em0 from XXX.XX.XX.XX (ttl=27263547, region=255) for goldflipper.net. type=A(1) class=1, answering goldflipper.net. Where the TTL is a bad value. I think I'm using the code the right way after the manpage ip(4): If the IP_RECVTTL option is enabled on a SOCK_DGRAM or SOCK_RAW socket, the recvmsg(2) call will return the TTL of the received datagram. The msg_control field in the msghdr structure points to a buffer that contains a cmsghdr structure followed by the TTL value. The cmsghdr fields have the following values: cmsg_len = CMSG_LEN(sizeof(struct in_addr)) cmsg_level = IPPROTO_IP cmsg_type = IP_RECVTTL And if I'm not mistaken the size of struct in_addr is 4. This looks like a documentation error. Actually, the data length is CMSG_LEN(sizeof(u_char)), as can be seen in src/netinet/ip_input.c:1744 and the implementation of sbcreatecontrol() in src/kern/uipc_socket2.c. Try the FreeBSD code, it looks that has a goof chanche of working. If this is indeed the case, I'd like to know so I can fix the man page. -Otto Since sourceforge is down I can't refer you to the webcvs but they still offer the files for download if you want to take a peak at the source code that'd be great! http://sourceforge.net/projects/wildcarddns/files/ Here are some snippets from my source code perhaps you can spot what I'm doing wrong? ... if (setsockopt(udp[i], IPPROTO_IP, IP_RECVTTL, on, sizeof(on)) 0) { ... #ifdef __FreeBSD__ u_char *ttlptr; #elif __OpenBSD__ struct in_addr *ttlptr; #else int *ttlptr; #endif u_int32_t received_ttl; ... #if __FreeBSD__ ttlptr = (u_char *) CMSG_DATA(cmsg); received_ttl = (u_int)*ttlptr; #elif __OpenBSD__ ttlptr = (struct in_addr *) CMSG_DATA(cmsg); memcpy(received_ttl, ttlptr, sizeof(u_int32_t)); #else ttlptr = (int *) CMSG_DATA(cmsg); received_ttl = (u_int)*ttlptr; #endif ... syslog(LOG_INFO, request on descriptor %u interface \%s\ from %s (ttl=%u, region=%d) for \%s\ type=%s class=%u, answering \%s\, so, ident[i], address, received_ttl, aregion, question-converted_name, get_dns_type(ntohs(question-hdr-qtype)), ntohs(question-hdr-qclass), replystring); ... Unfortunately this #define hell is a mess but it's the only way to get this portable among BSD's and Linux. I'm hoping someone can tell where I'm going wrong with this and why it's right sometimes and wrong the occasional time. Regards, -peter
Re: IP option IP_RECVTTL question
On Thu, Feb 03, 2011 at 01:51:47PM +0100, Otto Moerbeek wrote: cmsg_len = CMSG_LEN(sizeof(struct in_addr)) cmsg_level = IPPROTO_IP cmsg_type = IP_RECVTTL And if I'm not mistaken the size of struct in_addr is 4. This looks like a documentation error. Actually, the data length is CMSG_LEN(sizeof(u_char)), as can be seen in src/netinet/ip_input.c:1744 and the implementation of sbcreatecontrol() in src/kern/uipc_socket2.c. Try the FreeBSD code, it looks that has a goof chanche of working. If this is indeed the case, I'd like to know so I can fix the man page. -Otto Hi, At first glance it seems to be working with the FreeBSD code. On both i386 and amd64. Thanks! So it must be a documentation bug. Thanks for your help! -peter