diff options
| -rw-r--r-- | arp.c | 51 | ||||
| -rw-r--r-- | arp.h | 2 | ||||
| -rw-r--r-- | fwd.c | 10 | ||||
| -rw-r--r-- | ndp.c | 10 | ||||
| -rw-r--r-- | ndp.h | 1 |
5 files changed, 74 insertions, 0 deletions
@@ -150,3 +150,54 @@ void arp_send_init_req(const struct ctx *c) debug("Sending initial ARP request for guest MAC address"); tap_send_single(c, &req, sizeof(req)); } + +/** + * arp_announce() - Send an ARP announcement for an IPv4 host + * @c: Execution context + * @ip: IPv4 address we announce as owned by @mac + * @mac: MAC address to advertise for @ip + */ +void arp_announce(const struct ctx *c, struct in_addr *ip, + const unsigned char *mac) +{ + char ip_str[INET_ADDRSTRLEN]; + char mac_str[ETH_ADDRSTRLEN]; + struct { + struct ethhdr eh; + struct arphdr ah; + struct arpmsg am; + } __attribute__((__packed__)) msg; + + /* Ethernet header */ + msg.eh.h_proto = htons(ETH_P_ARP); + memcpy(msg.eh.h_dest, MAC_BROADCAST, sizeof(msg.eh.h_dest)); + memcpy(msg.eh.h_source, mac, sizeof(msg.eh.h_source)); + + /* ARP header */ + msg.ah.ar_op = htons(ARPOP_REQUEST); + msg.ah.ar_hrd = htons(ARPHRD_ETHER); + msg.ah.ar_pro = htons(ETH_P_IP); + msg.ah.ar_hln = ETH_ALEN; + msg.ah.ar_pln = 4; + + /* RFC5227, section 2.1.1, about Probe messages: "The client MUST fill + * in the 'sender hardware address' field of the ARP Request with the + * hardware address of the interface through which it is sending the + * packet. [...] The 'target hardware address' field is ignored and + * SHOULD be set to all zeroes." + * + * RFC5227, section 2.3: "An ARP Announcement is identical to the ARP + * Probe described above, except that now the sender and target IP + * addresses are both set to the host's newly selected IPv4 address." + */ + memcpy(msg.am.sha, mac, sizeof(msg.am.sha)); + memcpy(msg.am.sip, ip, sizeof(msg.am.sip)); + memcpy(msg.am.tha, MAC_ZERO, sizeof(msg.am.tha)); + memcpy(msg.am.tip, ip, sizeof(msg.am.tip)); + + inet_ntop(AF_INET, ip, ip_str, sizeof(ip_str)); + eth_ntop(mac, mac_str, sizeof(mac_str)); + debug("ARP announcement for %s / %s", ip_str, mac_str); + + tap_send_single(c, &msg, sizeof(msg)); +} @@ -22,5 +22,7 @@ struct arpmsg { int arp(const struct ctx *c, struct iov_tail *data); void arp_send_init_req(const struct ctx *c); +void arp_announce(const struct ctx *c, struct in_addr *ip, + const unsigned char *mac); #endif /* ARP_H */ @@ -27,6 +27,8 @@ #include "lineread.h" #include "flow_table.h" #include "netlink.h" +#include "arp.h" +#include "ndp.h" /* Ephemeral port range: values from RFC 6335 */ static in_port_t fwd_ephemeral_min = (1 << 15) + (1 << 14); @@ -140,6 +142,14 @@ void fwd_neigh_table_update(const struct ctx *c, const union inany_addr *addr, memcpy(&e->addr, addr, sizeof(*addr)); memcpy(e->mac, mac, ETH_ALEN); e->permanent = permanent; + + if (!memcmp(mac, c->our_tap_mac, ETH_ALEN)) + return; + + if (inany_v4(addr)) + arp_announce(c, inany_v4(addr), e->mac); + else + ndp_unsolicited_na(c, &addr->a6); } /** @@ -221,6 +221,16 @@ static void ndp_na(const struct ctx *c, const struct in6_addr *dst, } /** + * ndp_unsolicited_na() - Send unsolicited NA + * @c: Execution context + * @addr: IPv6 address to advertise + */ +void ndp_unsolicited_na(const struct ctx *c, const struct in6_addr *addr) +{ + ndp_na(c, &in6addr_ll_all_nodes, addr); +} + +/** * ndp_ra() - Send an NDP Router Advertisement (RA) message * @c: Execution context * @dst: IPv6 address to send the RA to @@ -12,5 +12,6 @@ int ndp(const struct ctx *c, const struct in6_addr *saddr, struct iov_tail *data); void ndp_timer(const struct ctx *c, const struct timespec *now); void ndp_send_init_req(const struct ctx *c); +void ndp_unsolicited_na(const struct ctx *c, const struct in6_addr *addr); #endif /* NDP_H */ |
