+ char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo)) + CMSG_SPACE(sizeof(int)) + 1];
+ struct cmsghdr *cmsgptr;
+ struct msghdr msg;
+ socklen_t len;
+ struct sockaddr_in from;
+ int flags = 0, ifindex = -1;
+ uint8_t ttl = 0;
+ struct in_pktinfo *inp = NULL;
+
+ if (u->eof) {
+ interface_close(iface);
+ uloop_timeout_set(&iface->reconnect, 1000);
+ return;
+ }
+
+ iov[0].iov_base = buffer;
+ iov[0].iov_len = sizeof(buffer);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = (struct sockaddr *) &from;
+ msg.msg_namelen = sizeof(struct sockaddr_in);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &cmsg;
+ msg.msg_controllen = sizeof(cmsg);
+
+ len = recvmsg(u->fd, &msg, flags);
+ if (len == -1) {
+ perror("read failed");
+ return;
+ }
+ for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
+ void *c = CMSG_DATA(cmsgptr);
+
+ switch (cmsgptr->cmsg_type) {
+ case IP_PKTINFO:
+ inp = ((struct in_pktinfo *) c);
+ break;
+
+ case IP_TTL:
+ ttl = (uint8_t) *((int *) c);
+ break;
+
+ default:
+ fprintf(stderr, "unknown cmsg %x\n", cmsgptr->cmsg_type);
+ return;
+ }
+ }
+
+ if (ttl != 255)
+ return;
+
+ if (debug > 1) {
+ char buf[256];
+
+ fprintf(stderr, "RX ipv4: %s\n", iface->name);
+ fprintf(stderr, " multicast: %d\n", iface->multicast);
+ inet_ntop(AF_INET, &from.sin_addr, buf, 256);
+ fprintf(stderr, " src %s:%d\n", buf, from.sin_port);
+ inet_ntop(AF_INET, &inp->ipi_spec_dst, buf, 256);
+ fprintf(stderr, " dst %s\n", buf);
+ inet_ntop(AF_INET, &inp->ipi_addr, buf, 256);
+ fprintf(stderr, " real %s\n", buf);
+ }
+
+ if (inp->ipi_ifindex != iface->ifindex)
+ fprintf(stderr, "invalid iface index %d != %d\n", ifindex, iface->ifindex);
+ else if (!interface_valid_src((void *) &iface->v4_addr, (void *) &iface->v4_netmask, (void *) &from.sin_addr, 4))
+ dns_handle_packet(iface, (struct sockaddr *) &from, from.sin_port, buffer, len);
+}
+
+static void
+read_socket6(struct uloop_fd *u, unsigned int events)
+{
+ struct interface *iface = container_of(u, struct interface, fd);
+ static uint8_t buffer[8 * 1024];
+ struct iovec iov[1];
+ char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)) + 1];