From d02e059ddcc00fba763c995818a5884ed8e97984 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Tue, 21 Jul 2020 10:48:24 +0200 Subject: passt: Add IPv6 and NDP support, further fixes for IPv4 CT Signed-off-by: Stefano Brivio --- passt.c | 502 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 425 insertions(+), 77 deletions(-) (limited to 'passt.c') diff --git a/passt.c b/passt.c index f5d88d9..57759e4 100644 --- a/passt.c +++ b/passt.c @@ -5,22 +5,22 @@ * Author: Stefano Brivio * License: GPLv2 * - * Grab Ethernet frames via AF_UNIX socket, build AF_INET sockets for each - * 5-tuple from ICMP, TCP, UDP packets, perform connection tracking and forward - * them with destination address NAT. Forward packets received on sockets back - * to the UNIX domain socket (typically, a tap file descriptor from qemu). + * Grab Ethernet frames via AF_UNIX socket, build AF_INET/AF_INET6 sockets for + * each 5-tuple from ICMP, TCP, UDP packets, perform connection tracking and + * forward them with destination address NAT. Forward packets received on + * sockets back to the UNIX domain socket (typically, a tap file descriptor from + * qemu). * * TODO: - * - steal packets from AF_INET sockets (using eBPF/XDP, or a new socket - * option): currently, incoming packets are also handled by in-kernel protocol - * handlers, so every incoming untracked TCP packet gets a RST. Workaround: + * - steal packets from AF_INET/AF_INET6 sockets (using eBPF/XDP, or a new + * socket option): currently, incoming packets are also handled by in-kernel + * protocol handlers, so every incoming untracked TCP packet gets a RST. + * Workaround: * iptables -A OUTPUT -m state --state INVALID,NEW,ESTABLISHED \ * -p tcp --tcp-flags RST RST -j DROP + * ip6tables -A OUTPUT -m state --state INVALID,NEW,ESTABLISHED \ + * -p tcp --tcp-flags RST RST -j DROP * - and use XDP sockmap on top of that to improve performance - * - add IPv6 support. Current workaround on the namespace or machine on the - * tap side: - * echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6 - * - reserve and translate ports * - aging and timeout/RST bookkeeping for connection tracking entries */ @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ #include "passt.h" #include "arp.h" #include "dhcp.h" +#include "ndp.h" #include "util.h" #define EPOLL_EVENTS 10 @@ -112,11 +114,13 @@ static void get_routes(struct ctx *c) struct sockaddr_nl addr = { .nl_family = AF_NETLINK, }; - int s, n, na, found = 0; struct nlmsghdr *nlh; struct rtattr *rta; struct rtmsg *rtm; char buf[BUFSIZ]; + int s, n, na; + + c->v6 = -1; s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (s < 0) { @@ -129,6 +133,7 @@ static void get_routes(struct ctx *c) goto out; } +v6: if (send(s, &req, sizeof(req), 0) < 0) { perror("netlink send"); goto out; @@ -141,35 +146,50 @@ static void get_routes(struct ctx *c) } nlh = (struct nlmsghdr *)buf; - if (nlh->nlmsg_type == NLMSG_DONE) - goto out; - - for ( ; NLMSG_OK(nlh, n) && found < 2; NLMSG_NEXT(nlh, n)) { + for ( ; NLMSG_OK(nlh, n); nlh = NLMSG_NEXT(nlh, n)) { rtm = (struct rtmsg *)NLMSG_DATA(nlh); - if (rtm->rtm_dst_len) + if (rtm->rtm_dst_len || + (rtm->rtm_family != AF_INET && rtm->rtm_family != AF_INET6)) continue; rta = (struct rtattr *)RTM_RTA(rtm); na = RTM_PAYLOAD(nlh); - for ( ; RTA_OK(rta, na) && found < 2; rta = RTA_NEXT(rta, na)) { - if (rta->rta_type == RTA_GATEWAY) { + for ( ; RTA_OK(rta, na); rta = RTA_NEXT(rta, na)) { + if (rta->rta_type == RTA_GATEWAY && + rtm->rtm_family == AF_INET && !c->v4) { memcpy(&c->gw4, RTA_DATA(rta), sizeof(c->gw4)); - found++; + c->v4 = 1; + } + + if (rta->rta_type == RTA_GATEWAY && + rtm->rtm_family == AF_INET6 && !c->v6) { + memcpy(&c->gw6, RTA_DATA(rta), sizeof(c->gw6)); + c->v6 = 1; } - if (rta->rta_type == RTA_OIF) { + if (rta->rta_type == RTA_OIF && !*c->ifn) { if_indextoname(*(unsigned *)RTA_DATA(rta), c->ifn); - found++; } } + + if (nlh->nlmsg_type == NLMSG_DONE) + break; + } + + if (c->v6 == -1) { + c->v6 = 0; + req.rtm.rtm_family = AF_INET6; + req.nlh.nlmsg_seq++; + recv(s, &buf, sizeof(buf), 0); + goto v6; } out: close(s); - if (found < 2) { + if (!(c->v4 || c->v6) || !*c->ifn) { fprintf(stderr, "No routing information\n"); exit(EXIT_FAILURE); } @@ -185,15 +205,16 @@ static void get_addrs(struct ctx *c) .ifr_addr.sa_family = AF_INET, }; struct ifaddrs *ifaddr, *ifa; - int s; + int s, v4 = 0, v6 = 0; if (getifaddrs(&ifaddr) == -1) { perror("getifaddrs"); goto out; } - for (ifa = ifaddr; ifa && !c->addr4; ifa = ifa->ifa_next) { + for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { struct sockaddr_in *in_addr; + struct sockaddr_in6 *in6_addr; if (strcmp(ifa->ifa_name, c->ifn)) continue; @@ -201,17 +222,28 @@ static void get_addrs(struct ctx *c) if (!ifa->ifa_addr) continue; - if (ifa->ifa_addr->sa_family != AF_INET) - continue; + if (ifa->ifa_addr->sa_family == AF_INET && !v4) { + in_addr = (struct sockaddr_in *)ifa->ifa_addr; + c->addr4 = in_addr->sin_addr.s_addr; + in_addr = (struct sockaddr_in *)ifa->ifa_netmask; + c->mask4 = in_addr->sin_addr.s_addr; + v4 = 1; + } else if (ifa->ifa_addr->sa_family == AF_INET6 && !v6) { + in6_addr = (struct sockaddr_in6 *)ifa->ifa_addr; + memcpy(&c->addr6, &in6_addr->sin6_addr, + sizeof(c->addr6)); + v6 = 1; + } - in_addr = (struct sockaddr_in *)ifa->ifa_addr; - c->addr4 = in_addr->sin_addr.s_addr; - in_addr = (struct sockaddr_in *)ifa->ifa_netmask; - c->mask4 = in_addr->sin_addr.s_addr; + if (v4 == c->v4 && v6 == c->v6) + break; } freeifaddrs(ifaddr); + if (v4 != c->v4 || v6 != c->v6) + goto out; + s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("socket SIOCGIFHWADDR"); @@ -239,55 +271,72 @@ out: */ static void get_dns(struct ctx *c) { - char buf[BUFSIZ], *p, *nl; - int dns4 = 0; + char buf[BUFSIZ], *p, *end; + int dns4 = 0, dns6 = 0; FILE *r; r = fopen("/etc/resolv.conf", "r"); - while (fgets(buf, BUFSIZ, r) && !dns4) { + while (fgets(buf, BUFSIZ, r) && !(dns4 && dns6)) { if (!strstr(buf, "nameserver ")) continue; p = strrchr(buf, ' '); - nl = strchr(buf, '\n'); - if (nl) - *nl = 0; + end = strpbrk(buf, "%\n"); + if (end) + *end = 0; if (p && inet_pton(AF_INET, p + 1, &c->dns4)) dns4 = 1; + if (p && inet_pton(AF_INET6, p + 1, &c->dns6)) + dns6 = 1; } fclose(r); - if (dns4) + if (dns4 || dns6) return; - fprintf(stderr, "Couldn't get IPv4 nameserver address\n"); + fprintf(stderr, "Couldn't get any nameserver address\n"); exit(EXIT_FAILURE); } /** - * sock4_l4() - Create and bind AF_INET socket for given L4, add to epoll list + * sock_l4() - Create and bind socket for given L4, add to epoll list * @c: Execution context + * @v: IP protocol, 4 or 6 * @proto: Protocol number, network order * @port: L4 port, network order * * Return: newly created socket, -1 on error */ -static int sock4_l4(struct ctx *c, uint16_t proto, uint16_t port) +static int sock_l4(struct ctx *c, int v, uint16_t proto, uint16_t port) { - struct sockaddr_in addr = { + struct sockaddr_in addr4 = { .sin_family = AF_INET, .sin_port = port, .sin_addr = { .s_addr = c->addr4 }, }; + struct sockaddr_in6 addr6 = { + .sin6_family = AF_INET6, + .sin6_port = port, + .sin6_addr = c->addr6, + }; struct epoll_event ev = { 0 }; - int fd; + const struct sockaddr *sa; + int fd, sl; - fd = socket(AF_INET, SOCK_RAW, proto); + fd = socket(v == 4 ? AF_INET : AF_INET6, SOCK_RAW, proto); if (fd < 0) { perror("L4 socket"); return -1; } - if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) < 0) { + if (v == 4) { + sa = (const struct sockaddr *)&addr4; + sl = sizeof(addr4); + } else { + sa = (const struct sockaddr *)&addr6; + sl = sizeof(addr6); + } + + if (bind(fd, sa, sl) < 0) { perror("L4 bind"); close(fd); return -1; @@ -304,7 +353,7 @@ static int sock4_l4(struct ctx *c, uint16_t proto, uint16_t port) } /** - * lookup4() - Look up socket entry from tap-sourced packet, create if missing + * lookup4() - Look up entry from tap-sourced IPv4 packet, create if missing * @c: Execution context * @eh: Packet buffer, Ethernet header * @@ -337,17 +386,21 @@ static int lookup4(struct ctx *c, const struct ethhdr *eh) } for (i = 0; i < CT_SIZE && ct[i].p; i++) { - if (iph->protocol == IPPROTO_ICMP) + if (iph->protocol == IPPROTO_ICMP && ct[i].p == IPPROTO_ICMP) one_icmp_fd = ct[i].fd; } if (i == CT_SIZE) { fprintf(stderr, "\nToo many sockets, aborting "); } else { - if (iph->protocol == IPPROTO_ICMP && one_icmp_fd) - ct[i].fd = one_icmp_fd; - else - ct[i].fd = sock4_l4(c, iph->protocol, th->source); + if (iph->protocol == IPPROTO_ICMP) { + if (one_icmp_fd) + ct[i].fd = one_icmp_fd; + else + ct[i].fd = sock_l4(c, 4, iph->protocol, 0); + } else { + ct[i].fd = sock_l4(c, 4, iph->protocol, th->source); + } fprintf(stderr, "\n(socket %i) New ", ct[i].fd); ct[i].p = iph->protocol; @@ -378,7 +431,103 @@ static int lookup4(struct ctx *c, const struct ethhdr *eh) } /** - * lookup4_r4() - Reverse look up connection tracking entry from incoming packet + * lookup6() - Look up entry from tap-sourced IPv6 packet, create if missing + * @c: Execution context + * @eh: Packet buffer, Ethernet header + * + * Return: -1 for unsupported or too many sockets, matching socket otherwise + */ +static int lookup6(struct ctx *c, const struct ethhdr *eh) +{ + struct ipv6hdr *ip6h = (struct ipv6hdr *)(eh + 1); + char buf_s[BUFSIZ], buf_d[BUFSIZ]; + struct ct6 *ct = c->map6; + int i, one_icmp_fd = 0; + struct tcphdr *th; + uint8_t proto; + + th = (struct tcphdr *)ipv6_l4hdr(ip6h, &proto); + if (!th) + return -1; + + if (proto != IPPROTO_ICMPV6 && proto != IPPROTO_TCP && + proto != IPPROTO_UDP) + return -1; + + for (i = 0; i < CT_SIZE; i++) { + if (ct[i].p != proto) + continue; + + if (memcmp(ct[i].hd, eh->h_dest, ETH_ALEN) || + memcmp(ct[i].hs, eh->h_source, ETH_ALEN) || + memcmp(&ct[i].sa, &ip6h->saddr, sizeof(ct[i].sa))) + continue; + + if (ct[i].p != IPPROTO_ICMPV6 && + ct[i].sp != th->source) + continue; + + if (ct[i].p == IPPROTO_ICMPV6 && + memcmp(&ct[i].da, &ip6h->daddr, sizeof(ct[i].da))) + continue; + + if (ct[i].p != IPPROTO_ICMPV6) { + memcpy(&ct[i].da, &ip6h->daddr, sizeof(ct[i].da)); + ct[i].dp = th->dest; + } + + return ct[i].fd; + } + + for (i = 0; i < CT_SIZE && ct[i].p; i++) { + if (proto == IPPROTO_ICMPV6 && ct[i].p == IPPROTO_ICMPV6) + one_icmp_fd = ct[i].fd; + } + + if (i == CT_SIZE) { + fprintf(stderr, "\nToo many sockets, aborting "); + } else { + if (proto == IPPROTO_ICMPV6) { + if (one_icmp_fd) + ct[i].fd = one_icmp_fd; + else + ct[i].fd = sock_l4(c, 6, proto, 0); + } else { + ct[i].fd = sock_l4(c, 6, proto, th->source); + } + + fprintf(stderr, "\n(socket %i) New ", ct[i].fd); + ct[i].p = proto; + memcpy(&ct[i].sa, &ip6h->saddr, sizeof(ct[i].sa)); + memcpy(&ct[i].da, &ip6h->daddr, sizeof(ct[i].da)); + if (ct[i].p != IPPROTO_ICMPV6) { + ct[i].sp = th->source; + ct[i].dp = th->dest; + } + memcpy(&ct[i].hd, eh->h_dest, ETH_ALEN); + memcpy(&ct[i].hs, eh->h_source, ETH_ALEN); + } + + if (proto == IPPROTO_ICMPV6) { + fprintf(stderr, "icmpv6 connection\n\tfrom %s\n" + "\tto %s\n\n", + inet_ntop(AF_INET6, &ct[i].sa, buf_s, sizeof(buf_s)), + inet_ntop(AF_INET6, &ct[i].da, buf_d, sizeof(buf_d))); + } else { + fprintf(stderr, "%s connection\n\tfrom [%s]:%i\n" + "\tto [%s]:%i\n\n", + getprotobynumber(proto)->p_name, + inet_ntop(AF_INET6, &ct[i].sa, buf_s, sizeof(buf_s)), + ntohs(th->source), + inet_ntop(AF_INET6, &ct[i].da, buf_d, sizeof(buf_d)), + ntohs(th->dest)); + } + + return (i == CT_SIZE) ? -1 : ct[i].fd; +} + +/** + * lookup_r4() - Reverse look up connection tracking entry for IPv4 packet * @ct: Connection tracking table * @fd: File descriptor that received the packet * @iph: Packet buffer, IP header @@ -403,13 +552,26 @@ struct ct4 *lookup_r4(struct ct4 *ct, int fd, struct iphdr *iph) } /** - * nat4_out() - Perform outgoing IPv4 address translation - * @addr: Source address to be used - * @iph: IP header + * lookup_r6() - Reverse look up connection tracking entry for IPv6 packet + * @ct: Connection tracking table + * @fd: File descriptor that received the packet + * + * Return: matching entry if any, NULL otherwise */ -static void nat4_out(unsigned long addr, struct iphdr *iph) +struct ct6 *lookup_r6(struct ct6 *ct, int fd, struct tcphdr *th) { - iph->saddr = addr; + int i; + + for (i = 0; i < CT_SIZE; i++) { + if (ct[i].fd != fd) + continue; + + if (ct[i].p == IPPROTO_ICMPV6 || + (ct[i].dp == th->source && ct[i].sp == th->dest)) + return &ct[i]; + } + + return NULL; } /** @@ -454,7 +616,7 @@ static void csum_tcp4(struct iphdr *iph) } /** - * tap4_handler() - Packet handler for tap file descriptor + * tap4_handler() - IPv4 packet handler for tap file descriptor * @c: Execution context * @len: Total L2 packet length * @in: Packet buffer, L2 headers @@ -502,8 +664,6 @@ static void tap4_handler(struct ctx *c, int len, char *in) else if (iph->protocol != IPPROTO_ICMP) return; - nat4_out(c->addr4, iph); - if (sendto(fd, (void *)th, len - sizeof(*eh) - iph->ihl * 4, 0, (struct sockaddr *)&addr, sizeof(addr)) < 0) perror("sendto"); @@ -511,7 +671,103 @@ static void tap4_handler(struct ctx *c, int len, char *in) } /** - * ext4_handler() - Packet handler for external routable interface + * tap6_handler() - IPv6 packet handler for tap file descriptor + * @c: Execution context + * @len: Total L2 packet length + * @in: Packet buffer, L2 headers + */ +static void tap6_handler(struct ctx *c, int len, char *in) +{ + struct ethhdr *eh = (struct ethhdr *)in; + struct ipv6hdr *ip6h = (struct ipv6hdr *)(eh + 1); + struct tcphdr *th; + struct udphdr *uh; + struct icmp6hdr *ih; + struct sockaddr_in6 addr = { + .sin6_family = AF_INET6, + .sin6_addr = ip6h->daddr, + }; + char buf_s[BUFSIZ], buf_d[BUFSIZ]; + uint8_t proto; + int fd; + + if (ndp(c, len, eh)) + return; + + fd = lookup6(c, eh); + if (fd == -1) + return; + + th = (struct tcphdr *)ipv6_l4hdr(ip6h, &proto); + uh = (struct udphdr *)th; + ih = (struct icmp6hdr *)th; + + if (proto == IPPROTO_ICMPV6) { + fprintf(stderr, "icmpv6 from tap: %s ->\n\t%s (socket %i)\n", + inet_ntop(AF_INET6, &ip6h->saddr, buf_s, sizeof(buf_s)), + inet_ntop(AF_INET6, &ip6h->daddr, buf_d, sizeof(buf_d)), + fd); + } else { + fprintf(stderr, "%s from tap: [%s]:%i\n" + "\t-> [%s]:%i (socket %i)\n", + getprotobynumber(proto)->p_name, + inet_ntop(AF_INET6, &ip6h->saddr, buf_s, sizeof(buf_s)), + ntohs(th->source), + inet_ntop(AF_INET6, &ip6h->daddr, buf_d, sizeof(buf_d)), + ntohs(th->dest), + fd); + } + + if (proto != IPPROTO_TCP && proto != IPPROTO_UDP && + proto != IPPROTO_ICMPV6) + return; + + ip6h->saddr = c->addr6; + + ip6h->hop_limit = proto; + ip6h->version = 0; + ip6h->nexthdr = 0; + memset(ip6h->flow_lbl, 0, 3); + + if (proto == IPPROTO_TCP) { + th->check = 0; + th->check = csum_ip4(ip6h, + len - ((intptr_t)th - (intptr_t)eh) + + sizeof(*ip6h)); + } else if (proto == IPPROTO_UDP) { + uh->check = 0; + uh->check = csum_ip4(ip6h, + len - ((intptr_t)uh - (intptr_t)eh) + + sizeof(*ip6h)); + } else if (proto == IPPROTO_ICMPV6) { + ih->icmp6_cksum = 0; + ih->icmp6_cksum = csum_ip4(ip6h, + len - ((intptr_t)ih - (intptr_t)eh) + + sizeof(*ip6h)); + } + + ip6h->version = 6; + ip6h->nexthdr = proto; + ip6h->hop_limit = 255; + + if (sendto(fd, (void *)th, len - ((intptr_t)th - (intptr_t)eh), 0, + (struct sockaddr *)&addr, sizeof(addr)) < 0) + perror("sendto"); + +} + +static void tap_handler(struct ctx *c, int len, char *in) +{ + struct ethhdr *eh = (struct ethhdr *)in; + + if (eh->h_proto == ntohs(ETH_P_IP) || eh->h_proto == ntohs(ETH_P_ARP)) + tap4_handler(c, len, in); + else if (eh->h_proto == ntohs(ETH_P_IPV6)) + tap6_handler(c, len, in); +} + +/** + * ext4_handler() - IPv4 packet handler for external routable interface * @c: Execution context * @fd: File descriptor that received the packet * @len: Total L3 packet length @@ -565,6 +821,85 @@ static void ext4_handler(struct ctx *c, int fd, int len, char *in) perror("send"); } +/** + * ext6_handler() - IPv6 packet handler for external routable interface + * @c: Execution context + * @fd: File descriptor that received the packet + * @len: Total L4 packet length + * @in: Packet buffer, L4 headers + */ +static int ext6_handler(struct ctx *c, int fd, int len, char *in) +{ + struct tcphdr *th = (struct tcphdr *)in; + struct udphdr *uh; + struct icmp6hdr *ih; + char buf_s[BUFSIZ], buf_d[BUFSIZ], buf[ETH_MAX_MTU] = { 0 }; + struct ethhdr *eh = (struct ethhdr *)buf; + struct ipv6hdr *ip6h = (struct ipv6hdr *)(eh + 1); + struct ct6 *entry; + + entry = lookup_r6(c->map6, fd, th); + if (!entry) + return 0; + + ip6h->daddr = entry->sa; + ip6h->saddr = entry->da; + memcpy(ip6h + 1, in, len); + ip6h->payload_len = htons(len); + + th = (struct tcphdr *)(ip6h + 1); + uh = (struct udphdr *)th; + ih = (struct icmp6hdr *)th; + ip6h->hop_limit = entry->p; + + if (entry->p == IPPROTO_TCP) { + th->check = 0; + th->check = csum_ip4(ip6h, len + sizeof(*ip6h)); + } else if (entry->p == IPPROTO_UDP) { + uh->check = 0; + uh->check = csum_ip4(ip6h, len + sizeof(*ip6h)); + } else if (entry->p == IPPROTO_ICMPV6) { + ih->icmp6_cksum = 0; + ih->icmp6_cksum = csum_ip4(ip6h, len + sizeof(*ip6h)); + } + + ip6h->version = 6; + ip6h->nexthdr = entry->p; + ip6h->hop_limit = 255; + + memcpy(eh->h_dest, entry->hs, ETH_ALEN); + memcpy(eh->h_source, entry->hd, ETH_ALEN); + eh->h_proto = ntohs(ETH_P_IPV6); + + if (entry->p == IPPROTO_ICMPV6) { + fprintf(stderr, "icmpv6 (socket %i) to tap: %s\n\t-> %s\n", + entry->fd, + inet_ntop(AF_INET6, &ip6h->saddr, buf_s, sizeof(buf_s)), + inet_ntop(AF_INET6, &ip6h->daddr, buf_d, + sizeof(buf_d))); + } else { + fprintf(stderr, "%s (socket %i) to tap: [%s]:%i\n" + "\t-> [%s]:%i\n", + getprotobynumber(entry->p)->p_name, + entry->fd, + inet_ntop(AF_INET6, &ip6h->saddr, buf_s, sizeof(buf_s)), + ntohs(th->source), + inet_ntop(AF_INET6, &ip6h->daddr, buf_d, sizeof(buf_d)), + ntohs(th->dest)); + } + + if (send(c->fd_unix, buf, len + sizeof(*ip6h) + sizeof(*eh), 0) < 0) + perror("send"); + + return 1; +} + +static void ext_handler(struct ctx *c, int fd, int len, char *in) +{ + if (!ext6_handler(c, fd, len, in)) + ext4_handler(c, fd, len, in); +} + /** * usage() - Print usage and exit * @name: Executable name @@ -585,8 +920,9 @@ void usage(const char *name) */ int main(int argc, char **argv) { - struct epoll_event events[EPOLL_EVENTS]; + char buf6[3][sizeof("0123:4567:89ab:cdef:0123:4567:89ab:cdef")]; char buf4[4][sizeof("255.255.255.255")]; + struct epoll_event events[EPOLL_EVENTS]; struct epoll_event ev = { 0 }; char buf[ETH_MAX_MTU]; struct ctx c = { 0 }; @@ -600,16 +936,27 @@ int main(int argc, char **argv) get_addrs(&c); get_dns(&c); - fprintf(stderr, "ARP:\n"); - fprintf(stderr, "\taddress: %02x:%02x:%02x:%02x:%02x:%02x from %s\n", - c.mac[0], c.mac[1], c.mac[2], c.mac[3], c.mac[4], c.mac[5], - c.ifn); - fprintf(stderr, "DHCP:\n"); - fprintf(stderr, "\tassign: %s, mask: %s, router: %s, DNS: %s\n\n", - inet_ntop(AF_INET, &c.addr4, buf4[0], sizeof(buf4[0])), - inet_ntop(AF_INET, &c.mask4, buf4[1], sizeof(buf4[1])), - inet_ntop(AF_INET, &c.gw4, buf4[2], sizeof(buf4[2])), - inet_ntop(AF_INET, &c.dns4, buf4[3], sizeof(buf4[3]))); + if (c.v4) { + fprintf(stderr, "ARP:\n"); + fprintf(stderr, "\taddress: %02x:%02x:%02x:%02x:%02x:%02x " + "from %s\n", c.mac[0], c.mac[1], c.mac[2], + c.mac[3], c.mac[4], c.mac[5], c.ifn); + fprintf(stderr, "DHCP:\n"); + fprintf(stderr, "\tassign:\t%s\n\tnmask:\t%s\n" + "\trouter:\t%s\n\tDNS:\t%s\n", + inet_ntop(AF_INET, &c.addr4, buf4[0], sizeof(buf4[0])), + inet_ntop(AF_INET, &c.mask4, buf4[1], sizeof(buf4[1])), + inet_ntop(AF_INET, &c.gw4, buf4[2], sizeof(buf4[2])), + inet_ntop(AF_INET, &c.dns4, buf4[3], sizeof(buf4[3]))); + } + if (c.v6) { + fprintf(stderr, "NDP:\n"); + fprintf(stderr, "\tassign:\t%s\n\trouter:\t%s\n\tDNS:\t%s\n", + inet_ntop(AF_INET6, &c.addr6, buf6[0], sizeof(buf6[0])), + inet_ntop(AF_INET6, &c.gw6, buf6[1], sizeof(buf6[1])), + inet_ntop(AF_INET6, &c.dns6, buf6[2], sizeof(buf6[2]))); + } + fprintf(stderr, "\n"); c.epollfd = epoll_create1(0); if (c.epollfd == -1) { @@ -620,13 +967,14 @@ int main(int argc, char **argv) fd_unix = sock_unix(); listen: listen(fd_unix, 1); + fprintf(stderr, + "You can now start qrap:\n\t" + "./qrap 42 kvm ... -net tap,fd=42 -net nic,model=virtio\n\n"); + c.fd_unix = accept(fd_unix, NULL, NULL); ev.events = EPOLLIN; ev.data.fd = c.fd_unix; epoll_ctl(c.epollfd, EPOLL_CTL_ADD, c.fd_unix, &ev); - fprintf(stderr, - "You can now start qrap:\n\t" - "./qrap 42 kvm ... -net tap,fd=42 -net nic,model=virtio\n\n"); loop: nfds = epoll_wait(c.epollfd, events, EPOLL_EVENTS, -1); @@ -654,9 +1002,9 @@ loop: } if (events[i].data.fd == c.fd_unix) - tap4_handler(&c, len, buf); + tap_handler(&c, len, buf); else - ext4_handler(&c, events[i].data.fd, len, buf); + ext_handler(&c, events[i].data.fd, len, buf); } goto loop; -- cgit v1.2.3