-
February 17th, 2010, 05:34 PM
#1
Strange UDP problem - BSD sockets
This is a problem with BSD sockets on Ubuntu. I hope this is not the wrong place to ask this.
I have a piece of code that should listen on DNS port 53 of the local machine, and handle DNS queries (responses and replies). If the code gets back a response with 0 answer sections, the code re-issues a query for a different DNS RR type. The code re-issues a query asking for a custom RR type. This packet is seen on the issuing machine's tcpdump, but not on the tcpdump of the machine running the resolver. All packets are sent using UDP.
Two observations:
1. If I let my piece of code sleep a second before sending the packet, all's successful! (I've commented out sleep in the code below).
2. If the application requesting a DNS query requests for the custom RR type (what should have been re-issued by my piece of code), the response is retrieved.
Please let me know if additional information would be useful
Thank you for your time,
Arun Madhavan
Code:
Socket creation:
m_udp_fd = socket(PF_INET, SOCK_DGRAM, 0);
if (m_udp_fd >= 0)
{
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(DNS_PORT);
// allow the socket to re-bind to the same port
do {
int ignore = 0;
if (setsockopt(m_udp_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&ignore,
sizeof(ignore)) < 0)
{
fprintf(stderr, "setsockopt with SO_REUSEADDR failed with error %d\n", GetLastError());
return false;
}
}
while(0);
// Windows non-blocking is done at create
#ifndef _MSC_VER
set_nonblocking(m_udp_fd);
#endif /* _MSC_VER */
// bind to the port
if (bind(m_udp_fd, (struct sockaddr *)&sin, sizeof(sin)) == 0)
{
eprintf("PANZER: port %d\n", sin.sin_port);
select_loop();
// this can fall through
}
}
void Resolver::set_nonblocking(int fd) {
long flags;
if ((flags = fcntl(fd, F_GETFL)) < 0)
err(1, "fcntl(F_GETFL)");
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
err(1, "fcntl(F_SETFL)");
}
Entry point of code:
if ((r = recvfrom(m_udp_fd, (char*)buf, sizeof(buf), 0,
(struct sockaddr *)&sin, &sz)) > 0)
{
DnsPacket *p ;
p = new DnsPacket(r);
p->add_bytes(buf, r);
if (p->parse())
{
read_packet(sin, *p);
}
else
{
delete p;
}
}
}
void Resolver::read_packet(struct sockaddr_in &from, DnsPacket &p)
{
DnsHeader& h = p.header();
// response packet
if (h.response())
{
int id = h.id();
DnsQuery *q = m_queries.get(id);
if (q == NULL)
{
delete &p;
}
else
{
q->add_response(p);
// sleep(1);
// forward packet
write_packet(q->dest(), q->packet_to_forward());
if (q->done())
{
int id = h.id();
m_queries.remove(id);
}
}
}
// packet is a question
else
{
// silently drop packets that aren't from localhost
if (from.sin_addr.s_addr == ntohl(INADDR_LOOPBACK))
{
DnsQuery *q = new DnsQuery(from, p);
// add the query to the LRU
int id = p.header().id();
m_queries.add(id, *q);
size_t len;
u_char *b = p.get_bytes(len);
write_packet(m_tRes, b, len);
}
else
{
delete &p;
}
}
}
void Resolver::write_packet(struct sockaddr_in &dst, DnsPacket &p)
{
size_t size;
u_char *bytes = p.get_bytes(size);
write_packet(dst, bytes, size);
}
void Resolver::write_packet(struct sockaddr_in &dst, u_char *b, size_t len)
{
bool sent = false;
//printf("trying to send to %x:%d\n", dst.sin_addr.s_addr, ntohs(dst.sin_port));
// attempt to write the packet if the queue is empty
if (m_send_q.empty())
{
sent = try_send(dst, b, len);
}
if (!sent)
{
enqueue(dst, b, len);
}
}
bool Resolver::try_send(struct sockaddr_in &dst, u_char *b, size_t len)
{
SSIZE_T w;
do
{
w = sendto(m_udp_fd, (char*)b, len, 0, (struct sockaddr *)&dst, sizeof(dst));
if (w > 0)
{
eprintf("sent to %x:%d\n", dst.sin_addr.s_addr, ntohs(dst.sin_port));
delete [] b;
}
}
while (w < 0 && errno == EINTR);
if (w == 0)
{
eprintf("socket closed while writing\n");
exit(1);
}
if (w < 0 && errno != EAGAIN)
{
int errorNum = GetLastError();
eprintf("error on socket while writing: %s/%d\n", strerror(errorNum), errorNum);
exit(1);
}
// return true only if we wrote the packet
if (w > 0)
{
return true;
}
return false;
}
-
February 17th, 2010, 05:37 PM
#2
Re: Strange UDP problem - BSD sockets
I forgot to add: The first time the DNS query is issued, the piece of code forwards it across. The piece of code re-issuing with custom record is where it fails. However, if the first DNS query is for the custom RR type, it works.
One more thing to note: The DNS packet for the re-issue by the piece of code has been verified with a hex dump, and it seems alright.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|