+ 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);
+ break;
+ }
+ }
+
+ if (0) {
+ char buf[256];
+
+ inet_ntop(AF_INET, &from.sin_addr, buf, 256);
+ fprintf(stderr, "%s:%s[%d]%s:%d\n", __FILE__, __func__, __LINE__, buf, from.sin_port);
+ inet_ntop(AF_INET, &inp->ipi_spec_dst, buf, 256);
+ fprintf(stderr, "%s:%s[%d]%s:%d\n", __FILE__, __func__, __LINE__, buf, from.sin_port);
+ inet_ntop(AF_INET, &inp->ipi_addr, buf, 256);
+ fprintf(stderr, "%s:%s[%d]%s:%d\n", __FILE__, __func__, __LINE__, buf, from.sin_port);
+ }
+
+ if (inp->ipi_ifindex != iface->ifindex)
+ fprintf(stderr, "invalid iface index %d != %d\n", ifindex, iface->ifindex);
+ else if (ttl == 255)
+ dns_handle_packet(iface, buffer, len, 0);
+}
+
+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)) + 1];