From 6ad12c206ccd36f20bed96561262f0561f6cb3dc Mon Sep 17 00:00:00 2001 From: David Clark Date: Mon, 12 Nov 2012 19:11:07 -0700 Subject: [PATCH] Added spoofing of ipv6 NDP Solicitations Ticket #42 --- honeyd.c | 19 +++++++++------ honeyd.h | 2 +- icmpv6.h | 15 ++++++++++++ ndp.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- ndp.h | 9 ++++++- tuple.h | 11 ++++++++- 6 files changed, 116 insertions(+), 14 deletions(-) diff --git a/honeyd.c b/honeyd.c index 1f1d83c..a086b4f 100644 --- a/honeyd.c +++ b/honeyd.c @@ -2886,22 +2886,21 @@ honeyd_dispatch(struct template *tmpl, struct ip_hdr *ip, u_short iplen) } void -honeyd_dispatch_ipv6(struct template *tmpl, struct ip6_hdr *ip, u_short iplen) +honeyd_dispatch_ipv6(struct tuple *summary, struct template *tmpl, struct ip6_hdr *ip, u_short iplen) { - struct tuple iphdr; - addr_pack(&iphdr.address_dst, ADDR_TYPE_IP6, IP6_ADDR_BITS, &ip->ip6_dst ,IP6_ADDR_LEN); - addr_pack(&iphdr.address_src, ADDR_TYPE_IP6, IP6_ADDR_BITS, &ip->ip6_src ,IP6_ADDR_LEN); + addr_pack(&summary->address_dst, ADDR_TYPE_IP6, IP6_ADDR_BITS, &ip->ip6_dst ,IP6_ADDR_LEN); + addr_pack(&summary->address_src, ADDR_TYPE_IP6, IP6_ADDR_BITS, &ip->ip6_src ,IP6_ADDR_LEN); switch(ip->ip6_nxt) { case IP_PROTO_TCP: - tcp_recv_cb(tmpl, (u_char *)ip + IP6_HDR_LEN, &iphdr, iplen - IP6_HDR_LEN); + tcp_recv_cb(tmpl, (u_char *)ip + IP6_HDR_LEN, summary, iplen - IP6_HDR_LEN); break; case IP_PROTO_UDP: // TODO ipv6 //udp_recv_cb(tmpl, (u_char *)ip, iplen); break; case IP_PROTO_ICMPV6: - icmpv6_recv_cb(tmpl, (u_char*)ip + IP6_HDR_LEN, &iphdr, iplen - IP6_HDR_LEN); + icmpv6_recv_cb(tmpl, (u_char*)ip + IP6_HDR_LEN, summary, iplen - IP6_HDR_LEN); break; default: // TODO ipv6 @@ -3328,7 +3327,13 @@ honeyd_recv_cb(u_char *ag, const struct pcap_pkthdr *pkthdr, const u_char *pkt) addr_pack(&addr, ADDR_TYPE_IP6, IP6_ADDR_BITS, &ip6->ip6_dst ,IP6_ADDR_LEN); struct template *t = template_find_best(addr_ntoa(&addr), NULL, 0); - honeyd_dispatch_ipv6(t, ip6, iplen); + + struct tuple summary; + addr_pack(&summary.linkLayer_src, ADDR_TYPE_ETH, ETH_ADDR_BITS, ð->eth_src,ETH_ADDR_LEN); + addr_pack(&summary.linkLayer_dst, ADDR_TYPE_ETH, ETH_ADDR_BITS, ð->eth_dst,ETH_ADDR_LEN); + summary.inter = inter; + + honeyd_dispatch_ipv6(&summary, t, ip6, iplen); return; } diff --git a/honeyd.h b/honeyd.h index c933e0c..91fa3d1 100644 --- a/honeyd.h +++ b/honeyd.h @@ -294,7 +294,7 @@ struct tuple *tuple_find(struct tree *, struct tuple *); void honeyd_ip_send(u_char *, u_int, struct spoof spoof); void honeyd_dispatch(struct template *, struct ip_hdr *, u_short); -void honeyd_dispatch_ipv6(struct template *, struct ip6_hdr *, u_short); +void honeyd_dispatch_ipv6(struct tuple *summary, struct template *, struct ip6_hdr *, u_short); char *honeyd_contoa(const struct tuple *); void honeyd_input(const struct interface *, struct ip_hdr *, u_short); diff --git a/icmpv6.h b/icmpv6.h index d8fef6c..389d37b 100644 --- a/icmpv6.h +++ b/icmpv6.h @@ -63,6 +63,10 @@ struct icmpv6_hdr { #define ICMPV6_INFOTYPE(type) (((type) & 0x80) != 0) +#define ICMPV6_NAFLAGS_ROUTER 0x4 +#define ICMPV6_NAFLAGS_SOLICITED 0x2 +#define ICMPV6_NAFLAGS_OVERRIDE 0x1 + /* * Echo message data */ @@ -119,4 +123,15 @@ union icmpv6_msg { memmove(&nd_pack_p->icmpv6_mac, &(srcmac), ETH_ADDR_LEN); \ } while (0) +#define icmpv6_pack_hdr_na_mac(hdr, targetip, targetmac) do { \ + struct icmpv6_msg_nd *nd_pack_p = (struct icmpv6_msg_nd *) \ + ((uint8_t *)(hdr) + ICMPV6_HDR_LEN); \ + icmpv6_pack_hdr(hdr, ICMPV6_NEIGHBOR_ADVERTISEMENT, 0); \ + nd_pack_p->icmpv6_flags = 0 | ICMPV6_NAFLAGS_SOLICITED | ICMPV6_NAFLAGS_OVERRIDE; \ + memmove(&nd_pack_p->icmpv6_target, &(targetip), IP6_ADDR_LEN); \ + nd_pack_p->icmpv6_option_type = 2; \ + nd_pack_p->icmpv6_option_length = 1; \ + memmove(&nd_pack_p->icmpv6_mac, &(targetmac), ETH_ADDR_LEN); \ +} while (0) + #endif /* DNET_ICMPV6_H */ diff --git a/ndp.c b/ndp.c index 13824ee..68ddcf3 100644 --- a/ndp.c +++ b/ndp.c @@ -68,7 +68,7 @@ #include "debug.h" /* For the physical (IP) address */ -static SPLAY_HEAD(pandptree, ndp_req) pa_ndp_reqs; +static SPLAY_HEAD(ndpTree, ndp_req) pa_ndp_reqs; static int pandp_compare(struct ndp_req *a, struct ndp_req *b) @@ -76,8 +76,25 @@ pandp_compare(struct ndp_req *a, struct ndp_req *b) return (addr_cmp(&a->pa, &b->pa)); } -SPLAY_PROTOTYPE(pandptree, ndp_req, next_pa, pandp_compare); -SPLAY_GENERATE(pandptree, ndp_req, next_pa, pandp_compare); +SPLAY_PROTOTYPE(ndpTree, ndp_req, next_pa, pandp_compare); +SPLAY_GENERATE(ndpTree, ndp_req, next_pa, pandp_compare); + + +struct ndp_req * +ndp_find(struct addr *addr) +{ + struct ndp_req tmp, *res = NULL; + + if (addr->addr_type == ADDR_TYPE_IP6) { + tmp.pa = *addr; + res = SPLAY_FIND(ndpTree, &pa_ndp_reqs, &tmp); + } else { + errx(1, "%s: lookup for unsupported address type", __func__); + } + + return (res); +} + void ndp_init(void) @@ -104,7 +121,7 @@ ndp_new(struct interface *inter, if (pa != NULL) { req->pa = *pa; - SPLAY_INSERT(pandptree, &pa_ndp_reqs, req); + SPLAY_INSERT(ndpTree, &pa_ndp_reqs, req); } // TODO ipv6: Do we want another MAC -> thing tree here? Need to think about this. Maybe refactor the hardware mapping out. @@ -123,11 +140,60 @@ ndp_new(struct interface *inter, return (req); } +void ndp_send_advertisement(eth_t *eth, + struct addr linkLayerSource, struct addr linkLayerDestination, + struct addr ipLayerSource, struct addr ipLayerDestination, + struct addr advertisementLinkTarget, struct addr advertisementIpTarget) +{ + + printf("Ndp advertisement details {\nipLayerSource: %s\nipLayerDestination: %s \nadvertisementLinkTarget: %s\nadvertisementIpTarget: %s\n}\n", addr_ntoa(&ipLayerSource), addr_ntoa(&ipLayerDestination), addr_ntoa(&advertisementLinkTarget), addr_ntoa(&advertisementIpTarget)); + uint packetLength = ETH_HDR_LEN + IP6_HDR_LEN + ICMPV6_HDR_LEN + sizeof(struct icmpv6_msg_nd); + u_char pkt[packetLength]; + + eth_pack_hdr(pkt, linkLayerDestination.addr_eth, linkLayerSource.addr_eth, ETH_TYPE_IPV6); + ip6_pack_hdr(pkt + ETH_HDR_LEN, 0, 0, 32, IP_PROTO_ICMPV6, IP6_HLIM_MAX, ipLayerSource.__addr_u.__ip6, ipLayerDestination.__addr_u.__ip6); + icmpv6_pack_hdr_na_mac(pkt + ETH_HDR_LEN + IP6_HDR_LEN, advertisementIpTarget.__addr_u.__ip6, advertisementLinkTarget.__addr_u.__eth); + + ip6_checksum(pkt + ETH_HDR_LEN, packetLength - ETH_HDR_LEN); + + syslog(LOG_INFO, "ndp reply %s is-at %s", addr_ntoa(&advertisementIpTarget), addr_ntoa(&advertisementLinkTarget)); + + if (eth_send(eth, pkt, sizeof(pkt)) != sizeof(pkt)) + syslog(LOG_ERR, "couldn't send packet: %m"); +} + void ndp_recv_cb(struct tuple *summary, const struct icmpv6_msg_nd *query) { + struct template *tmpl; + struct addr *linkLayerSource; struct addr queryIP; + struct ndp_req *req; addr_pack(&queryIP, ADDR_TYPE_IP6, IP6_ADDR_BITS, &query->icmpv6_target ,IP6_ADDR_LEN); printf("Got a request for IP %s\n", addr_ntoa(&queryIP)); + tmpl = template_find(addr_ntoa(&queryIP)); + req = ndp_find(&queryIP); + + // Ignore it if isn't a template IP + if (req == NULL || tmpl == NULL) + { + return; + } + + if (tmpl->ethernet_addr == NULL) + linkLayerSource = &summary->inter->if_ent.intf_link_addr; + else + linkLayerSource = tmpl->ethernet_addr; + + printf("Creating reply now\n"); + + ndp_send_advertisement(summary->inter->if_eth, + *linkLayerSource, summary->linkLayer_src, + queryIP, summary->address_src, + *linkLayerSource, queryIP); + + } + + diff --git a/ndp.h b/ndp.h index 3673a45..c1d3c15 100644 --- a/ndp.h +++ b/ndp.h @@ -62,10 +62,17 @@ struct ndp_req { void ndp_init(); -struct ndp_req *ndp_new(struct interface *, +struct ndp_req *ndp_new(struct interface *inter, struct addr *src_pa, struct addr *src_ha, struct addr *pa, struct addr *ha); + +void ndp_send_advertisement(eth_t *eth, + struct addr linkLayerSource, struct addr linkLayerDestination, + struct addr ipLayerSource, struct addr ipLayerDestination, + struct addr advertisementLinkTarget, struct addr advertisementIpTarget); + +struct ndp_req * ndp_find(struct addr *addr); void ndp_recv_cb(struct tuple *summary, const struct icmpv6_msg_nd *query); diff --git a/tuple.h b/tuple.h index 56eb27b..ebf7589 100644 --- a/tuple.h +++ b/tuple.h @@ -5,7 +5,6 @@ #ifndef TUPLE_H_ #define TUPLE_H_ - /* * For subsystems, we need to be able to schedule a callback that hands * the subsytem a file descriptor to the new connection. However, Honeyd @@ -30,9 +29,19 @@ struct tuple { SPLAY_ENTRY(tuple) node; TAILQ_ENTRY(tuple) next; + // IP layer src/dst packet come from struct addr address_src; struct addr address_dst; + // Link layer src/dst packet came from + struct addr linkLayer_src; + struct addr linkLayer_dst; + + // Interface packet came from + struct interface *inter; + + // Used for TCP/UDP and ICMP + // TODO: Using this for ICMP is hackish. Make it a union for type/code. uint16_t sport; uint16_t dport;