#include "iface.h"
#include "socket.h"
+static void dispatch_packet(flxServer *s, flxDnsPacket *p, struct sockaddr *sa, gint iface, gint ttl) {
+ g_assert(s);
+ g_assert(p);
+ g_assert(sa);
+ g_assert(iface > 0);
+
+ if (ttl != 255) {
+ flxInterface *i = flx_interface_monitor_get_interface(s->monitor, iface);
+ g_warning("Recieved packet with invalid TTL on interface '%s'.", i ? i->name : "unknown");
+ return;
+ }
+
+ if (sa->sa_family == AF_INET6) {
+ static const unsigned char ipv4_in_ipv6[] = {
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF };
+
+ if (memcmp(((struct sockaddr_in6*) sa)->sin6_addr.s6_addr, ipv4_in_ipv6, sizeof(ipv4_in_ipv6)) == 0) {
+
+ /* This is an IPv4 address encapsulated in IPv6, so let's ignore it. */
+ return;
+ }
+ }
+
+ g_message("Recieved packet");
+
+}
+
+static gboolean work(flxServer *s) {
+ struct sockaddr_in6 sa6;
+ struct sockaddr_in sa;
+ flxDnsPacket *p;
+ gint iface = -1;
+ guint8 ttl;
+
+ g_assert(s);
+
+ if (s->pollfd_ipv4.revents & G_IO_IN) {
+ if ((p = flx_recv_dns_packet_ipv4(s->fd_ipv4, &sa, &iface, &ttl)))
+ dispatch_packet(s, p, (struct sockaddr*) &sa, iface, ttl);
+ }
+
+ if (s->pollfd_ipv6.revents & G_IO_IN) {
+ if ((p = flx_recv_dns_packet_ipv6(s->fd_ipv6, &sa6, &iface, &ttl)))
+ dispatch_packet(s, p, (struct sockaddr*) &sa6, iface, ttl);
+ }
+
+ return TRUE;
+}
+
+static gboolean prepare_func(GSource *source, gint *timeout) {
+ g_assert(source);
+ g_assert(timeout);
+
+ *timeout = -1;
+ return FALSE;
+}
+
+static gboolean check_func(GSource *source) {
+ flxServer* s;
+ g_assert(source);
+
+ s = *((flxServer**) (((guint8*) source) + sizeof(GSource)));
+ g_assert(s);
+
+ return (s->pollfd_ipv4.revents | s->pollfd_ipv6.revents) & (G_IO_IN | G_IO_HUP | G_IO_ERR);
+}
+
+static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer user_data) {
+ flxServer* s;
+ g_assert(source);
+
+ s = *((flxServer**) (((guint8*) source) + sizeof(GSource)));
+ g_assert(s);
+
+ return work(s);
+}
+
static void add_default_entries(flxServer *s) {
gint length = 0;
struct utsname utsname;
flxServer *flx_server_new(GMainContext *c) {
gchar *hn, *e;
flxServer *s;
+
+ static GSourceFuncs source_funcs = {
+ prepare_func,
+ check_func,
+ dispatch_func,
+ NULL,
+ NULL,
+ NULL
+ };
s = g_new(flxServer, 1);
add_default_entries(s);
+ s->source = g_source_new(&source_funcs, sizeof(GSource) + sizeof(flxServer*));
+ *((flxServer**) (((guint8*) s->source) + sizeof(GSource))) = s;
+
+ memset(&s->pollfd_ipv4, 0, sizeof(s->pollfd_ipv4));
+ s->pollfd_ipv4.fd = s->fd_ipv4;
+ s->pollfd_ipv4.events = G_IO_IN|G_IO_ERR|G_IO_HUP;
+ g_source_add_poll(s->source, &s->pollfd_ipv4);
+
+ memset(&s->pollfd_ipv6, 0, sizeof(s->pollfd_ipv6));
+ s->pollfd_ipv6.fd = s->fd_ipv6;
+ s->pollfd_ipv6.events = G_IO_IN|G_IO_ERR|G_IO_HUP;
+ g_source_add_poll(s->source, &s->pollfd_ipv6);
+
+ g_source_attach(s->source, s->context);
+
return s;
}
g_hash_table_destroy(s->rrset_by_name);
flx_time_event_queue_free(s->time_event_queue);
- g_main_context_unref(s->context);
if (s->fd_ipv4 >= 0)
close(s->fd_ipv4);
close(s->fd_ipv6);
g_free(s->hostname);
+
+ g_source_destroy(s->source);
+ g_source_unref(s->source);
+ g_main_context_unref(s->context);
+
g_free(s);
}
gint flx_open_socket_ipv4(void) {
struct ip_mreqn mreq;
struct sockaddr_in sa, local;
- int fd = -1, ttl, yes;
+ int fd = -1, ttl, yes, no;
mdns_mcast_group_ipv4(&sa);
}
ttl = 255;
- if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
+ if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
g_warning("IP_MULTICAST_TTL failed: %s\n", strerror(errno));
goto fail;
}
ttl = 255;
- if (setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
+ if (setsockopt(fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
g_warning("IP_TTL failed: %s\n", strerror(errno));
goto fail;
}
goto fail;
}
+ no = 0;
+ if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &no, sizeof(no)) < 0) {
+ g_warning("IP_MULTICAST_LOOP failed: %s\n", strerror(errno));
+ goto fail;
+ }
+
+
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(MDNS_PORT);
mreq.imr_address.s_addr = htonl(INADDR_ANY);
mreq.imr_ifindex = 0;
- if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
+ if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
g_warning("IP_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
goto fail;
}
yes = 1;
- if (setsockopt(fd, IPPROTO_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
+ if (setsockopt(fd, SOL_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
g_warning("IP_RECVTTL failed: %s\n", strerror(errno));
goto fail;
}
yes = 1;
- if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
+ if (setsockopt(fd, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
g_warning("IP_PKTINFO failed: %s\n", strerror(errno));
goto fail;
}
gint flx_open_socket_ipv6(void) {
struct ipv6_mreq mreq;
struct sockaddr_in6 sa, local;
- int fd = -1, ttl, yes;
+ int fd = -1, ttl, yes, no;
mdns_mcast_group_ipv6(&sa);
}
ttl = 255;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
+ if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
g_warning("IPV6_MULTICAST_HOPS failed: %s\n", strerror(errno));
goto fail;
}
ttl = 255;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
+ if (setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
g_warning("IPV6_UNICAST_HOPS failed: %s\n", strerror(errno));
goto fail;
}
goto fail;
}
+ yes = 1;
+ if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
+ g_warning("IPV6_V6ONLY failed: %s\n", strerror(errno));
+ goto fail;
+ }
+
+ no = 0;
+ if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &no, sizeof(no)) < 0) {
+ g_warning("IPV6_MULTICAST_LOOP failed: %s\n", strerror(errno));
+ goto fail;
+ }
+
memset(&local, 0, sizeof(local));
local.sin6_family = AF_INET6;
local.sin6_port = htons(MDNS_PORT);
mreq.ipv6mr_multiaddr = sa.sin6_addr;
mreq.ipv6mr_interface = 0;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
+ if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
g_warning("IPV6_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
goto fail;
}
yes = 1;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
+ if (setsockopt(fd, SOL_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
g_warning("IPV6_HOPLIMIT failed: %s\n", strerror(errno));
goto fail;
}
yes = 1;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
+ if (setsockopt(fd, SOL_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
g_warning("IPV6_PKTINFO failed: %s\n", strerror(errno));
goto fail;
}
}
}
- g_assert(found_iface && found_ttl);
+ g_assert(found_iface);
+ g_assert(found_ttl);
return p;
p->size = (size_t) l;
*ret_ttl = 0;
-
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) {
- if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IPV6_HOPLIMIT) {
+
+ g_message("pre");
+
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT) {
*ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
found_ttl = TRUE;
}
- if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IPV6_PKTINFO) {
- *ret_iface = ((struct in_pktinfo*) CMSG_DATA(cmsg))->ipi_ifindex;
+ if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
+ *ret_iface = ((struct in6_pktinfo*) CMSG_DATA(cmsg))->ipi6_ifindex;
found_iface = TRUE;
}
+
+ g_message("-- %u -- %u\n", cmsg->cmsg_level, cmsg->cmsg_type);
}
- g_assert(found_iface && found_ttl);
+ g_message("post");
+
+
+ g_assert(found_iface);
+ g_assert(found_ttl);
return p;