/* ettercap -- send the the wire functions Copyright (C) ALoR & NaGA This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #if defined(OS_DARWIN) || defined(OS_BSD) #include #endif #include #include #include #include #include #include #define PCAP_TIMEOUT 10 /* globals */ u_int8 MEDIA_BROADCAST[MEDIA_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; u_int8 ARP_BROADCAST[MEDIA_ADDR_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static SLIST_HEAD (, build_entry) builders_table; struct build_entry { u_int8 dlt; FUNC_BUILDER_PTR(builder); SLIST_ENTRY (build_entry) next; }; /* protos */ libnet_ptag_t ec_build_link_layer(u_int8 dlt, u_int8 *dst, u_int16 proto, libnet_t* l); static pthread_mutex_t send_mutex = PTHREAD_MUTEX_INITIALIZER; #define SEND_LOCK do{ pthread_mutex_lock(&send_mutex); } while(0) #define SEND_UNLOCK do{ pthread_mutex_unlock(&send_mutex); } while(0) /*******************************************/ /* * send the packet at layer 3 * the eth header will be handled by the kernel */ int send_to_L3(struct packet_object *po) { libnet_ptag_t t; libnet_t *l; char tmp[MAX_ASCII_ADDR_LEN]; int c; switch(ntohs(po->L3.src.addr_type)) { case AF_INET: l = EC_GBL_LNET->lnet_IP4; break; #ifdef WITH_IPV6 case AF_INET6: l = EC_GBL_LNET->lnet_IP6; break; #endif default: l = NULL; break; } /* Do not send the packet if corresponding * libnet handler is not initialized */ if(l == NULL) return -E_NOTHANDLED; SEND_LOCK; t = libnet_build_data(po->fwd_packet, po->fwd_len, l, 0); ON_ERROR(t, -1, "libnet_build_data: %s", libnet_geterror(l)); c = libnet_write(l); //ON_ERROR(c, -1, "libnet_write %d (%d): %s", po->fwd_len, c, libnet_geterror(l)); if (c == -1) USER_MSG("SEND L3 ERROR: %d byte packet (%04x:%02x) destined to %s was not forwarded (%s)\n", po->fwd_len, ntohs(po->L3.proto), po->L4.proto, ip_addr_ntoa(&po->L3.dst, tmp), libnet_geterror(l)); /* clear the pblock */ libnet_clear_packet(l); SEND_UNLOCK; return c; } /* * send the packet at layer 2 * this can be used to send ARP messages */ int send_to_L2(struct packet_object *po) { return send_to_iface(po, EC_GBL_IFACE); } /* * send the packet to the bridge */ int send_to_bridge(struct packet_object *po) { return send_to_iface(po, EC_GBL_BRIDGE); } int send_to_iface(struct packet_object *po, struct iface_env *iface) { libnet_ptag_t t; int c; libnet_t *l; if(iface->unoffensive) return -E_INVALID; /* if not lnet warn the developer ;) */ BUG_IF(iface->lnet == NULL); l = iface->lnet; SEND_LOCK; t = libnet_build_data(po->packet, po->len, l, 0); ON_ERROR(t, -1, "libnet_build_data: %s", libnet_geterror(l)); c = libnet_write(l); ON_ERROR(c, -1, "libnet_write %d (%d): %s", po->len, c, libnet_geterror(l)); /* clear the pblock */ libnet_clear_packet(l); SEND_UNLOCK; return c; } /* * we MUST not sniff packets sent by us at link layer. * expecially useful in bridged sniffing. * * so we have to find a solution... */ void capture_only_incoming(pcap_t *p, libnet_t *l) { (void)p; (void)l; #ifdef OS_LINUX /* * a dirty hack to use the same socket for pcap and libnet. * both the structures contains a "int fd" field representing the socket. * we can close the fd opened by libnet and use the one already in use by pcap. */ DEBUG_MSG("hack_pcap_lnet (before) pcap %d | lnet %d", pcap_fileno(p), l->fd); /* needed to avoid double execution (for portstealing) */ if (pcap_fileno(p) == l->fd) return; /* close the lnet socket */ close(libnet_getfd(l)); /* use the socket opened by pcap */ l->fd = pcap_fileno(p); DEBUG_MSG("hack_pcap_lnet (after) pcap %d | lnet %d", pcap_fileno(p), l->fd); #endif #ifdef OS_BSD /* * under BSD we cannot hack the fd as in linux... * pcap opens the /dev/bpf in O_RDONLY and lnet needs O_RDWR * * so (if supported: only FreeBSD) we can set the BIOCSSEESENT to 0 to * see only incoming packets * but this is unconfortable, because we will not able to sniff ourself. */ #ifdef OS_BSD_FREE int val = 0; DEBUG_MSG("hack_pcap_lnet: setting BIOCSSEESENT on pcap handler"); /* set it to 0 to capture only incoming traffic */ ioctl(pcap_fileno(p), BIOCSSEESENT, &val); #else DEBUG_MSG("hack_pcap_lnet: not applicable on this OS"); #endif #endif #ifdef OS_DARWIN int val = 0; DEBUG_MSG("hack_pcap_lnet: setting BIOCSSEESENT on pcap handler"); /* not all darwin versions support BIOCSSEESENT */ #ifdef BIOCSSEESENT ioctl(pcap_fileno(p), BIOCSSEESENT, &val); #endif #endif #ifdef OS_SOLARIS DEBUG_MSG("hack_pcap_lnet: not applicable on this OS"); #endif #ifdef OS_CYGWIN DEBUG_MSG("hack_pcap_lnet: not applicable on this OS"); #endif } /* * register a builder in the table * a builder is a function to create a link layer header. */ void add_builder(u_int8 dlt, FUNC_BUILDER_PTR(builder)) { struct build_entry *e; SAFE_CALLOC(e, 1, sizeof(struct build_entry)); e->dlt = dlt; e->builder = builder; SLIST_INSERT_HEAD(&builders_table, e, next); return; } /* * build the header calling the registered * function for the current media */ libnet_ptag_t ec_build_link_layer(u_int8 dlt, u_int8 *dst, u_int16 proto, libnet_t* l) { struct build_entry *e; SLIST_FOREACH (e, &builders_table, next) { if (e->dlt == dlt) { return e->builder(dst, proto, l); } } /* on error return -1 */ return -1; } /* * helper function to send out an ARP packet */ int send_arp(u_char type, struct ip_addr *sip, u_int8 *smac, struct ip_addr *tip, u_int8 *tmac) { libnet_ptag_t t; libnet_t *l; int c; /* if not lnet warn the developer ;) */ BUG_IF(EC_GBL_IFACE->lnet == NULL); l = EC_GBL_IFACE->lnet; SEND_LOCK; /* ARP uses 00:00:00:00:00:00 broadcast */ if (type == ARPOP_REQUEST && tmac == MEDIA_BROADCAST) tmac = ARP_BROADCAST; /* create the ARP header */ t = libnet_build_arp( ARPHRD_ETHER, /* hardware addr */ ETHERTYPE_IP, /* protocol addr */ MEDIA_ADDR_LEN, /* hardware addr size */ IP_ADDR_LEN, /* protocol addr size */ type, /* operation type */ smac, /* sender hardware addr */ (u_char *)&(sip->addr), /* sender protocol addr */ tmac, /* target hardware addr */ (u_char *)&(tip->addr), /* target protocol addr */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); /* pblock id */ ON_ERROR(t, -1, "libnet_build_arp: %s", libnet_geterror(l)); /* MEDIA uses ff:ff:ff:ff:ff:ff broadcast */ if (type == ARPOP_REQUEST && tmac == ARP_BROADCAST) tmac = MEDIA_BROADCAST; /* add the media header */ t = ec_build_link_layer(EC_GBL_PCAP->dlt, tmac, ETHERTYPE_ARP, l); if (t == -1) FATAL_ERROR("Interface not suitable for layer2 sending"); /* send the packet */ c = libnet_write(l); ON_ERROR(c, -1, "libnet_write (%d): %s", c, libnet_geterror(l)); /* clear the pblock */ libnet_clear_packet(l); SEND_UNLOCK; return c; } /* * helper function to send out an ICMP PORT UNREACH packet at layer 3 */ int send_L3_icmp_unreach(struct packet_object *po) { libnet_ptag_t t; int c; libnet_t *l; /* if not lnet warn the developer ;) */ BUG_IF(EC_GBL_LNET->lnet_IP4 == 0); l = EC_GBL_LNET->lnet_IP4; SEND_LOCK; /* create the ICMP header */ t = libnet_build_icmpv4_echo( 3, /* type */ 3, /* code */ 0, /* checksum */ htons(EC_MAGIC_16), /* identification number */ htons(EC_MAGIC_16), /* sequence number */ po->L3.header, /* payload */ po->L3.len + 8, /* payload size */ l, /* libnet handle */ 0); /* pblock id */ ON_ERROR(t, -1, "libnet_build_icmpv4_echo: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* create the IP header */ t = libnet_build_ipv4( LIBNET_IPV4_H + LIBNET_ICMPV4_ECHO_H, /* length */ 0, /* TOS */ htons(EC_MAGIC_16), /* IP ID */ 0, /* IP Frag */ 64, /* TTL */ IPPROTO_ICMP, /* protocol */ 0, /* checksum */ *po->L3.dst.addr32, /* source IP */ *po->L3.src.addr32, /* destination IP */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); ON_ERROR(t, -1, "libnet_build_ipv4: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* send the packet to Layer 3 */ c = libnet_write(l); ON_ERROR(c, -1, "libnet_write (%d): %s", c, libnet_geterror(l)); /* clear the pblock */ libnet_clear_packet(l); SEND_UNLOCK; return c; } /* * helper function to send out an ICMP ECHO packet at layer 3 */ int send_L3_icmp(u_char type, struct ip_addr *sip, struct ip_addr *tip) { libnet_ptag_t t; int c; libnet_t *l; /* if not lnet warn the developer ;) */ BUG_IF(EC_GBL_LNET->lnet_IP4 == 0); l = EC_GBL_LNET->lnet_IP4; SEND_LOCK; /* create the ICMP header */ t = libnet_build_icmpv4_echo( type, /* type */ 0, /* code */ 0, /* checksum */ htons(EC_MAGIC_16), /* identification number */ htons(EC_MAGIC_16), /* sequence number */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); /* pblock id */ ON_ERROR(t, -1, "libnet_build_icmpv4_echo: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* create the IP header */ t = libnet_build_ipv4( LIBNET_IPV4_H + LIBNET_ICMPV4_ECHO_H, /* length */ 0, /* TOS */ htons(EC_MAGIC_16), /* IP ID */ 0, /* IP Frag */ 64, /* TTL */ IPPROTO_ICMP, /* protocol */ 0, /* checksum */ *sip->addr32, /* source IP */ *tip->addr32, /* destination IP */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); ON_ERROR(t, -1, "libnet_build_ipv4: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* send the packet to Layer 3 */ c = libnet_write(l); ON_ERROR(c, -1, "libnet_write (%d): %s", c, libnet_geterror(l)); /* clear the pblock */ libnet_clear_packet(l); SEND_UNLOCK; return c; } int send_L3_icmp_echo(struct ip_addr *src, struct ip_addr *tgt) { return send_L3_icmp(ICMP_ECHO, src, tgt); } /* * helper function to send out an ICMP ECHO packet at layer 2 */ int send_L2_icmp_echo(u_char type, struct ip_addr *sip, struct ip_addr *tip, u_int8 *tmac) { libnet_ptag_t t; int c; libnet_t *l; /* if not lnet warn the developer ;) */ BUG_IF(EC_GBL_IFACE->lnet == 0); l = EC_GBL_IFACE->lnet; SEND_LOCK; /* create the ICMP header */ t = libnet_build_icmpv4_echo( type, /* type */ 0, /* code */ 0, /* checksum */ htons(EC_MAGIC_16), /* identification number */ htons(EC_MAGIC_16), /* sequence number */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); /* pblock id */ ON_ERROR(t, -1, "libnet_build_icmpv4_echo: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* create the IP header */ t = libnet_build_ipv4( LIBNET_IPV4_H + LIBNET_ICMPV4_ECHO_H, /* length */ 0, /* TOS */ htons(EC_MAGIC_16), /* IP ID */ 0, /* IP Frag */ 64, /* TTL */ IPPROTO_ICMP, /* protocol */ 0, /* checksum */ *sip->addr32, /* source IP */ *tip->addr32, /* destination IP */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); ON_ERROR(t, -1, "libnet_build_ipv4: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* add the media header */ t = ec_build_link_layer(EC_GBL_PCAP->dlt, tmac, ETHERTYPE_IP, l); if (t == -1) FATAL_ERROR("Interface not suitable for layer2 sending"); /* send the packet to Layer 2 */ c = libnet_write(l); ON_ERROR(c, -1, "libnet_write (%d): %s", c, libnet_geterror(l)); /* clear the pblock */ libnet_clear_packet(l); SEND_UNLOCK; return c; } /* * helper function to send out an ICMP REDIRECT packet * the header are created on the source packet PO. */ int send_icmp_redir(u_char type, struct ip_addr *sip, struct ip_addr *gw, struct packet_object *po) { libnet_ptag_t t; libnet_t *l; struct libnet_ipv4_hdr *ip; int c; /* if not lnet warn the developer ;) */ BUG_IF(EC_GBL_IFACE->lnet == 0); l = EC_GBL_IFACE->lnet; /* retrieve the old ip header */ ip = (struct libnet_ipv4_hdr *)po->L3.header; SEND_LOCK; /* create the fake ip header for the icmp payload */ t = libnet_build_ipv4( LIBNET_IPV4_H + 8, //ntohs(ip->ip_len), /* original len */ ip->ip_tos, /* original tos */ ntohs(ip->ip_id), /* original id */ ntohs(ip->ip_off), /* original fragments */ ip->ip_ttl, /* original ttl */ ip->ip_p, /* original proto */ ip->ip_sum, /* original checksum */ ip->ip_src.s_addr, /* original source */ ip->ip_dst.s_addr, /* original dest */ po->L4.header, /* the 64 bit of the original datagram */ 8, /* payload size */ l, 0); ON_ERROR(t, -1, "libnet_build_ipv4: %s", libnet_geterror(l)); /* create the ICMP header */ t = libnet_build_icmpv4_redirect( ICMP_REDIRECT, /* type */ type, /* code */ 0, /* checksum */ *gw->addr32, /* gateway ip */ NULL, /* payload */ 0, /* payload len */ l, /* libnet handle */ 0); /* pblock id */ ON_ERROR(t, -1, "libnet_build_icmpv4_redirect: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* create the IP header */ t = libnet_build_ipv4( LIBNET_IPV4_H + LIBNET_ICMPV4_REDIRECT_H + LIBNET_IPV4_H + 8, /* length */ 0, /* TOS */ htons(EC_MAGIC_16), /* IP ID */ 0, /* IP Frag */ 64, /* TTL */ IPPROTO_ICMP, /* protocol */ 0, /* checksum */ *sip->addr32, /* source IP */ *po->L3.src.addr32, /* destination IP */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); ON_ERROR(t, -1, "libnet_build_ipv4: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* add the media header */ t = ec_build_link_layer(EC_GBL_PCAP->dlt, po->L2.src, ETHERTYPE_IP, l); if (t == -1) FATAL_ERROR("Interface not suitable for layer2 sending"); /* * send the packet to Layer 2 * (sending icmp redirect is not permitted at layer 3) */ c = libnet_write(l); ON_ERROR(c, -1, "libnet_write (%d): %s", c, libnet_geterror(l)); /* clear the pblock */ libnet_clear_packet(l); SEND_UNLOCK; return c; } #ifdef WITH_IPV6 int send_L3_icmp6_echo(struct ip_addr *sip, struct ip_addr *tip) { libnet_ptag_t t; struct libnet_in6_addr src, dst; int c; libnet_t *l; BUG_IF(EC_GBL_LNET->lnet_IP6 == 0); l = EC_GBL_LNET->lnet_IP6; SEND_LOCK; memcpy(&src, sip->addr, sizeof(src)); memcpy(&dst, tip->addr, sizeof(dst)); t = libnet_build_icmpv6_echo(ICMP6_ECHO_REQUEST, /* type */ 0, /* code */ 0, /* checksum */ EC_MAGIC_16, /* id */ 0, /* sequence number */ NULL, /* data */ 0, /* its size */ l, /* handle */ 0); ON_ERROR(t, -1, "libnet_build_icmpv6_echo: %s", libnet_geterror(l)); libnet_toggle_checksum(l, t, LIBNET_ON); t = libnet_build_ipv6(0, /* tc */ 0, /* flow label */ LIBNET_ICMPV6_H, /* next header size */ IPPROTO_ICMPV6, /* next header */ 255, /* hop limit */ src, /* source */ dst, /* destination */ NULL, /* payload and size */ 0, l, /* handle */ 0); /* ptag */ ON_ERROR(t, -1, "libnet_build_ipv6: %s", libnet_geterror(l)); c = libnet_write(l); ON_ERROR(c, -1, "libnet_write: %s", libnet_geterror(l)); libnet_clear_packet(l); SEND_UNLOCK; return c; } int send_L2_icmp6_echo(struct ip_addr *sip, struct ip_addr *tip, u_int8 *tmac) { libnet_ptag_t t; struct libnet_in6_addr src, dst; int c; libnet_t *l; BUG_IF(EC_GBL_IFACE->lnet == NULL); l = EC_GBL_IFACE->lnet; SEND_LOCK; memcpy(&src, sip->addr, sizeof(src)); memcpy(&dst, tip->addr, sizeof(dst)); t = libnet_build_icmpv6_echo(ICMP6_ECHO_REQUEST, /* type */ 0, /* code */ 0, /* checksum */ EC_MAGIC_16, /* id */ 0, /* sequence number */ NULL, /* data */ 0, /* its size */ l, /* handle */ 0); ON_ERROR(t, -1, "libnet_build_icmpv6_echo: %s", libnet_geterror(l)); libnet_toggle_checksum(l, t, LIBNET_ON); t = libnet_build_ipv6(0, /* tc */ 0, /* flow label */ LIBNET_ICMPV6_H, /* next header size */ IPPROTO_ICMPV6, /* next header */ 255, /* hop limit */ src, /* source */ dst, /* destination */ NULL, /* payload and size */ 0, l, /* handle */ 0); /* ptag */ ON_ERROR(t, -1, "libnet_build_ipv6: %s", libnet_geterror(l)); /* add the media header */ t = ec_build_link_layer(EC_GBL_PCAP->dlt, tmac, ETHERTYPE_IPV6, l); if (t == -1) FATAL_ERROR("Interface not suitable for layer2 sending"); c = libnet_write(l); ON_ERROR(c, -1, "libnet_write: %s", libnet_geterror(l)); libnet_clear_packet(l); SEND_UNLOCK; return c; } /* * send IP packet with an unknown header option * RFC2460 conforming hosts, respond with a ICMPv6 parameter problem * message even those not intended to respond to ICMP echos */ int send_L2_icmp6_echo_opt(struct ip_addr *sip, struct ip_addr *tip, u_int8* o_data, u_int32 o_len, u_int8 *tmac) { libnet_ptag_t t; struct libnet_in6_addr src, dst; int c, h = 0; libnet_t *l; BUG_IF(EC_GBL_IFACE->lnet == NULL); l = EC_GBL_IFACE->lnet; SEND_LOCK; memcpy(&src, sip->addr, sizeof(src)); memcpy(&dst, tip->addr, sizeof(dst)); t = libnet_build_icmpv6_echo(ICMP6_ECHO_REQUEST, /* type */ 0, /* code */ 0, /* checksum */ EC_MAGIC_16, /* id */ 0, /* sequence number */ NULL, /* data */ 0, /* its size */ l, /* handle */ 0); ON_ERROR(t, -1, "libnet_build_icmpv6_echo: %s", libnet_geterror(l)); libnet_toggle_checksum(l, t, LIBNET_ON); t = libnet_build_ipv6_destopts(IPPROTO_ICMPV6, /* next header */ LIBNET_IPV6_DESTOPTS_H / 8, /* lenth */ o_data, /* payload */ o_len, /* payload length */ l, /* handle */ 0); ON_ERROR(t, -1, "libnet_build_ipv6_destopts: %s", libnet_geterror(l)); h = LIBNET_IPV6_DESTOPTS_H + o_len + LIBNET_ICMPV6_H; t = libnet_build_ipv6(0, /* tc */ 0, /* flow label */ h, /* next header size */ IPPROTO_DSTOPTS, /* next header */ 255, /* hop limit */ src, /* source */ dst, /* destination */ NULL, /* payload and size */ 0, l, /* handle */ 0); /* ptag */ ON_ERROR(t, -1, "libnet_build_ipv6: %s", libnet_geterror(l)); /* add the media header */ t = ec_build_link_layer(EC_GBL_PCAP->dlt, tmac, ETHERTYPE_IPV6, l); if (t == -1) FATAL_ERROR("Interface not suitable for layer2 sending"); c = libnet_write(l); ON_ERROR(c, -1, "libnet_write: %s", libnet_geterror(l)); libnet_clear_packet(l); SEND_UNLOCK; return c; } /* * Sends neighbor solicitation request (like arp request with ipv4) * macaddr parameter allows to add sender's mac address. This is an option for unicast requests. * See RFC4861 for more information. */ int send_L2_icmp6_nsol(struct ip_addr *sip, struct ip_addr *tip, struct ip_addr *req, u_int8 *macaddr, u_int8 *tmac) { libnet_ptag_t t; int c, h = 0; struct libnet_in6_addr src, dst, r; libnet_t *l; BUG_IF(EC_GBL_IFACE->lnet == NULL); l = EC_GBL_IFACE->lnet; SEND_LOCK; memcpy(&src, sip->addr, sizeof(src)); memcpy(&dst, tip->addr, sizeof(dst)); memcpy(&r, req->addr, sizeof(r)); if(macaddr != NULL) { t = libnet_build_icmpv6_ndp_opt(ND_OPT_SOURCE_LINKADDR, /* Address type */ macaddr, /* MAC address */ MEDIA_ADDR_LEN, /* Address length */ l, /* libnet handle */ 0); /* ptag */ ON_ERROR(t, -1, "libnet_build_icmpv6_ndp_opt: %s", libnet_geterror(l)); /* base header size + MAC address size */ h += LIBNET_ICMPV6_NDP_OPT_H + 6; } t = libnet_build_icmpv6_ndp_nsol(ND_NEIGHBOR_SOLICIT, /* type */ 0, /* code */ 0, /* checksum */ r, /* target address */ NULL, /* payload */ 0, /* its size */ l, /* libnet handler */ 0); /* ptag */ ON_ERROR(t, -1, "libnet_build_icmpv6_ndp_nsol: %s", libnet_geterror(l)); libnet_toggle_checksum(l, t, LIBNET_ON); h += LIBNET_ICMPV6_NDP_NSOL_H; t = libnet_build_ipv6(0, /* tc */ 0, /* flow label */ h, /* length */ IPPROTO_ICMP6, /* proto */ 255, /* hop limit */ src, /* source address */ dst, /* target address */ NULL, /* payload */ 0, /* its size */ l, /* handle */ 0); /* ptag */ ON_ERROR(t, -1, "libnet_build_ipv6: %s", libnet_geterror(l)); /* add the media header */ t = ec_build_link_layer(EC_GBL_PCAP->dlt, tmac, ETHERTYPE_IPV6, l); if (t == -1) FATAL_ERROR("Interface not suitable for layer2 sending"); c = libnet_write(l); ON_ERROR(c, -1, "libnet_write: %s", libnet_geterror(l)); libnet_clear_packet(l); SEND_UNLOCK; return c; } int send_L2_icmp6_nadv(struct ip_addr *sip, struct ip_addr *tip, u_int8 *macaddr, int router, u_int8 *tmac) { libnet_ptag_t t; int c, h = 0; struct libnet_in6_addr src, dst; int flags; libnet_t *l; BUG_IF(EC_GBL_IFACE->lnet == NULL); l = EC_GBL_IFACE->lnet; SEND_LOCK; memcpy(&src, sip->addr, sizeof(src)); memcpy(&dst, tip->addr, sizeof(dst)); t = libnet_build_icmpv6_ndp_opt(ND_OPT_TARGET_LINKADDR, /* Address type */ macaddr, /* MAC address */ MEDIA_ADDR_LEN, /* Address length */ l, /* libnet handle */ 0); /* ptag */ ON_ERROR(t, -1, "libnet_build_icmpv6_ndp_lla: %s", libnet_geterror(l)); h += LIBNET_ICMPV6_NDP_OPT_H + 6; flags = ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE; if(router) flags |= ND_NA_FLAG_ROUTER; t = libnet_build_icmpv6_ndp_nadv(ND_NEIGHBOR_ADVERT, /* type */ 0, /* code */ 0, /* checksum */ flags, /* flags */ src, /* address */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); /* ptag */ ON_ERROR(t, -1, "libnet_build_icmpv6_ndp_nadv: %s", libnet_geterror(l)); libnet_toggle_checksum(l, t, LIBNET_ON); h += LIBNET_ICMPV6_NDP_NADV_H; t = libnet_build_ipv6(0, /* tc */ 0, /* flow label */ h, /* length */ IPPROTO_ICMP6, /* proto */ 255, /* hop limit */ src, /* source address */ dst, /* target address */ NULL, /* payload */ 0, /* its size */ l, /* handle */ 0); /* ptag */ ON_ERROR(t, -1, "libnet_build_ipv6: %s", libnet_geterror(l)); /* add the media header */ t = ec_build_link_layer(EC_GBL_PCAP->dlt, tmac, ETHERTYPE_IPV6, l); if (t == -1) FATAL_ERROR("Interface not suitable for layer2 sending"); c = libnet_write(l); ON_ERROR(c, -1, "libnet_write: %s", libnet_geterror(l)); libnet_clear_packet(l); SEND_UNLOCK; return c; } #endif /* WITH_IPV6 */ /* * send a dhcp reply to tmac/tip */ int send_dhcp_reply(struct ip_addr *sip, struct ip_addr *tip, u_int8 *tmac, u_int8 *dhcp_hdr, u_int8 *options, size_t optlen) { libnet_ptag_t t; int c; libnet_t *l; /* if not lnet warn the developer ;) */ BUG_IF(EC_GBL_IFACE->lnet == 0); l = EC_GBL_IFACE->lnet; SEND_LOCK; /* add the dhcp options */ t = libnet_build_data( options, /* the options */ optlen, /* options len */ l, /* libnet handle */ 0); /* libnet ptag */ ON_ERROR(t, -1, "libnet_build_data: %s", libnet_geterror(l)); /* create the dhcp header */ t = libnet_build_data( dhcp_hdr, /* the header */ LIBNET_DHCPV4_H, /* dhcp len */ l, /* libnet handle */ 0); /* libnet ptag */ ON_ERROR(t, -1, "libnet_build_data: %s", libnet_geterror(l)); /* create the udp header */ t = libnet_build_udp( 67, /* source port */ 68, /* destination port */ LIBNET_UDP_H + LIBNET_DHCPV4_H + optlen, /* packet size */ 0, /* checksum */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); /* libnet id */ ON_ERROR(t, -1, "libnet_build_udp: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* create the IP header */ t = libnet_build_ipv4( LIBNET_IPV4_H + LIBNET_UDP_H + LIBNET_DHCPV4_H + optlen, /* length */ 0, /* TOS */ htons(EC_MAGIC_16), /* IP ID */ 0, /* IP Frag */ 64, /* TTL */ IPPROTO_UDP, /* protocol */ 0, /* checksum */ *sip->addr32, /* source IP */ *tip->addr32, /* destination IP */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); ON_ERROR(t, -1, "libnet_build_ipv4: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* add the media header */ t = ec_build_link_layer(EC_GBL_PCAP->dlt, tmac, ETHERTYPE_IP, l); if (t == -1) FATAL_ERROR("Interface not suitable for layer2 sending"); /* * send the packet to Layer 2 * (sending icmp redirect is not permitted at layer 3) */ c = libnet_write(l); ON_ERROR(c, -1, "libnet_write (%d): %s", c, libnet_geterror(l)); /* clear the pblock */ libnet_clear_packet(l); SEND_UNLOCK; return c; } /* * send a mdns reply */ int send_mdns_reply(struct iface_env *iface, u_int16 dport, struct ip_addr *sip, struct ip_addr *tip, u_int8 *tmac, u_int16 id, u_int8 *data, size_t datalen, u_int16 anws_rr, u_int16 auth_rr, u_int16 addi_rr) { libnet_ptag_t t; int c, proto, ethertype; libnet_t *l; proto = ntohs(sip->addr_type); /* if not lnet warn the developer ;) */ BUG_IF(iface->lnet == 0); l = iface->lnet; SEND_LOCK; /* create the dns packet */ t = libnet_build_dnsv4( LIBNET_UDP_DNSV4_H, /* TCP or UDP */ id, /* id */ 0x8400, /* standard reply, no error */ 0, /* num_q */ anws_rr, /* num_anws_rr */ auth_rr, /* num_auth_rr */ addi_rr, /* num_addi_rr */ data, datalen, l, /* libnet handle */ 0); /* libnet id */ ON_ERROR(t, -1, "libnet_build_dns: %s", libnet_geterror(l)); /* create the udp header */ t = libnet_build_udp( 5353, /* source port */ htons(dport), /* destination port */ LIBNET_UDP_H + LIBNET_UDP_DNSV4_H + datalen, /* packet size */ 0, /* checksum */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); /* libnet id */ ON_ERROR(t, -1, "libnet_build_udp: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* create the IP header */ switch (proto) { case AF_INET: { t = libnet_build_ipv4( LIBNET_IPV4_H + LIBNET_UDP_H + LIBNET_UDP_DNSV4_H + datalen, /* length */ 0, /* TOS */ htons(EC_MAGIC_16), /* IP ID */ 0, /* IP Frag */ 255, /* TTL */ IPPROTO_UDP, /* protocol */ 0, /* checksum */ *sip->addr32, /* source IP */ *tip->addr32, /* destination IP */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); ON_ERROR(t, -1, "libnet_build_ipv4: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* set Ethertype to IPv4 */ ethertype = ETHERTYPE_IP; break; } #ifdef WITH_IPV6 case AF_INET6: { struct libnet_in6_addr src, dst; memcpy(&src, sip->addr, sizeof(src)); memcpy(&dst, tip->addr, sizeof(dst)); t = libnet_build_ipv6( 0, /* traffic class */ 0, /* flow label */ LIBNET_UDP_H + LIBNET_UDP_DNSV4_H + datalen, /* payload length */ IPPROTO_UDP, /* next header */ 255, /* hop limit */ src, /* source IP */ dst, /* destination IP */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); ON_ERROR(t, -1, "libnet_build_ipv6: %s", libnet_geterror(l)); /* set Ethertype to IPv6 */ ethertype = ETHERTYPE_IPV6; break; } #endif }; /* add the media header */ t = ec_build_link_layer(EC_GBL_PCAP->dlt, tmac, ethertype, l); if (t == -1) FATAL_ERROR("Interface not suitable for layer2 sending"); /* send the packet to Layer 2 */ c = libnet_write(l); ON_ERROR(c, -1, "libnet_write (%d): %s", c, libnet_geterror(l)); /* clear the pblock */ libnet_clear_packet(l); SEND_UNLOCK; return c; } /* * send a dns reply */ int send_dns_reply(struct iface_env *iface, u_int16 dport, struct ip_addr *sip, struct ip_addr *tip, u_int8 *tmac, u_int16 id, u_int8 *data, size_t datalen, u_int16 anws_rr, u_int16 auth_rr, u_int16 addi_rr) { libnet_ptag_t t; int c, proto, ethertype; libnet_t *l; proto = ntohs(sip->addr_type); /* if not lnet warn the developer ;) */ BUG_IF(iface->lnet == 0); l = iface->lnet; SEND_LOCK; /* create the dns packet */ t = libnet_build_dnsv4( LIBNET_UDP_DNSV4_H, /* TCP or UDP */ id, /* id */ 0x8400, /* standard reply, no error */ 1, /* num_q */ anws_rr, /* num_anws_rr */ auth_rr, /* num_auth_rr */ addi_rr, /* num_addi_rr */ data, datalen, l, /* libnet handle */ 0); /* libnet id */ ON_ERROR(t, -1, "libnet_build_dns: %s", libnet_geterror(l)); /* create the udp header */ t = libnet_build_udp( 53, /* source port */ htons(dport), /* destination port */ LIBNET_UDP_H + LIBNET_UDP_DNSV4_H + datalen, /* packet size */ 0, /* checksum */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); /* libnet id */ ON_ERROR(t, -1, "libnet_build_udp: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* create the IP header */ switch (proto) { case AF_INET: { t = libnet_build_ipv4( LIBNET_IPV4_H + LIBNET_UDP_H + LIBNET_UDP_DNSV4_H + datalen, /* length */ 0, /* TOS */ htons(EC_MAGIC_16), /* IP ID */ 0, /* IP Frag */ 64, /* TTL */ IPPROTO_UDP, /* protocol */ 0, /* checksum */ *sip->addr32, /* source IP */ *tip->addr32, /* destination IP */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); ON_ERROR(t, -1, "libnet_build_ipv4: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* set Ethertype to IPv4 */ ethertype = ETHERTYPE_IP; break; } #ifdef WITH_IPV6 case AF_INET6: { struct libnet_in6_addr src, dst; memcpy(&src, sip->addr, sizeof(src)); memcpy(&dst, tip->addr, sizeof(dst)); t = libnet_build_ipv6( 0, /* traffic class */ 0, /* flow label */ LIBNET_UDP_H + LIBNET_UDP_DNSV4_H + datalen, /* payload length */ IPPROTO_UDP, /* next header */ 255, /* hop limit */ src, /* source IP */ dst, /* destination IP */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); ON_ERROR(t, -1, "libnet_build_ipv6: %s", libnet_geterror(l)); /* set Ethertype to IPv6 */ ethertype = ETHERTYPE_IPV6; break; } #endif }; /* add the media header */ t = ec_build_link_layer(EC_GBL_PCAP->dlt, tmac, ethertype, l); if (t == -1) FATAL_ERROR("Interface not suitable for layer2 sending"); /* send the packet to Layer 2 */ c = libnet_write(l); ON_ERROR(c, -1, "libnet_write (%d): %s", c, libnet_geterror(l)); /* clear the pblock */ libnet_clear_packet(l); SEND_UNLOCK; return c; } /* * send an udp packet */ int send_udp(struct ip_addr *sip, struct ip_addr *tip, u_int8 *tmac, u_int16 sport, u_int16 dport, u_int8 *payload, size_t length) { libnet_ptag_t t; libnet_t *l; int c, proto, ethertype; proto = ntohs(sip->addr_type); l = EC_GBL_IFACE->lnet; BUG_IF(EC_GBL_IFACE->lnet == 0); SEND_LOCK; /* * libnet_build_udp(uint16_t sp, uint16_t dp, uint16_t len, uint16_t sum, const uint8_t *payload, uint32_t payload_s, libnet_t *l, libnet_ptag_t ptag) */ t = libnet_build_udp( htons(sport), htons(dport), LIBNET_UDP_H + length, 0, payload, length, l, 0); ON_ERROR(t, -1, "libnet_build_udp: %s", libnet_geterror(l)); /* auto calculate checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* create IP header */ switch(proto) { case AF_INET: { t = libnet_build_ipv4( LIBNET_IPV4_H + LIBNET_UDP_H + length, /* length */ 0, /* TOS */ htons(EC_MAGIC_16), /* IP ID */ 0, /* IP FRAG */ 64, /* TTL */ IPPROTO_UDP, /* protocol */ 0, /* checksum */ *sip->addr32, /* source IP */ *tip->addr32, /* destination IP */ NULL, 0, /* payload size */ l, 0); libnet_toggle_checksum(l, t, LIBNET_ON); /* set Ethertype to IPv4 */ ethertype = ETHERTYPE_IP; break; } #ifdef WITH_IPV6 case AF_INET6: { struct libnet_in6_addr src, dst; memcpy(&src, sip->addr, sizeof(src)); memcpy(&dst, tip->addr, sizeof(dst)); t = libnet_build_ipv6( 0, /* tc */ 0, /* flow label */ LIBNET_UDP_H + length, /* payload length */ IPPROTO_UDP, /* protocol */ 255, /* hop limit */ src, /* source */ dst, /* destination */ NULL, /* payload */ 0, /* its length */ l, /* handle */ 0); /* ptag */ /* set Ethertype to IPv6 */ ethertype = ETHERTYPE_IPV6; break; } #endif }; ON_ERROR(t, -1, "libnet_build_ipvX: %s", libnet_geterror(l)); /* add the media header */ t = ec_build_link_layer(EC_GBL_PCAP->dlt, tmac, ethertype, l); if (t == -1) FATAL_ERROR("Interface not suitable for layer2 sending"); /* send the packet to Layer 3 */ c = libnet_write(l); ON_ERROR(c, -1, "libnet_write (%d): %s", c, libnet_geterror(l)); /* clear the block */ libnet_clear_packet(l); SEND_UNLOCK; return c; } /* * send a tcp packet */ int send_tcp(struct ip_addr *sip, struct ip_addr *tip, u_int16 sport, u_int16 dport, u_int32 seq, u_int32 ack, u_int8 flags, u_int8 *payload, size_t length) { libnet_ptag_t t; libnet_t *l; int proto; int c; proto = ntohs(sip->addr_type); l = (proto == AF_INET) ? EC_GBL_LNET->lnet_IP4 : EC_GBL_LNET->lnet_IP6; /* if not lnet warn the developer ;) */ BUG_IF(l == NULL); SEND_LOCK; t = libnet_build_tcp( ntohs(sport), /* source port */ ntohs(dport), /* destination port */ ntohl(seq), /* sequence number */ ntohl(ack), /* acknowledgement num */ flags, /* control flags */ 32767, /* window size */ 0, /* checksum */ 0, /* urgent pointer */ LIBNET_TCP_H + length, /* TCP packet size */ payload, /* payload */ length, /* payload size */ l, /* libnet handle */ 0); /* libnet id */ ON_ERROR(t, -1, "libnet_build_tcp: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* create the IP header */ switch(proto) { case AF_INET: { t = libnet_build_ipv4( LIBNET_IPV4_H + LIBNET_TCP_H, /* length */ 0, /* TOS */ htons(EC_MAGIC_16), /* IP ID */ 0, /* IP Frag */ 64, /* TTL */ IPPROTO_TCP, /* protocol */ 0, /* checksum */ *sip->addr32, /* source IP */ *tip->addr32, /* destination IP */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); libnet_toggle_checksum(l, t, LIBNET_ON); break; } #ifdef WITH_IPV6 case AF_INET6: { struct libnet_in6_addr src, dst; memcpy(&src, sip->addr, sizeof(src)); memcpy(&dst, tip->addr, sizeof(dst)); t = libnet_build_ipv6( 0, /* tc */ 0, /* flow label */ LIBNET_TCP_H, /* payload length */ IPPROTO_TCP, /* protocol */ 255, /* hop limit */ src, /* source address */ dst, /* destination address */ NULL, /* payload */ 0, /* its length */ l, /* handle */ 0); /* ptag */ break; } #endif }; ON_ERROR(t, -1, "libnet_build_ipvX: %s", libnet_geterror(l)); /* send the packet to Layer 3 */ c = libnet_write(l); ON_ERROR(c, -1, "libnet_write (%d): %s", c, libnet_geterror(l)); /* clear the pblock */ libnet_clear_packet(l); SEND_UNLOCK; return c; } /* * similar to send_tcp but the user can specify the destination mac addresses */ int send_tcp_ether(u_int8 *dmac, struct ip_addr *sip, struct ip_addr *tip, u_int16 sport, u_int16 dport, u_int32 seq, u_int32 ack, u_int8 flags) { libnet_ptag_t t; int c, proto, ethertype; libnet_t *l; proto = ntohs(sip->addr_type); /* if not lnet warn the developer ;) */ BUG_IF(EC_GBL_IFACE->lnet == 0); l = EC_GBL_IFACE->lnet; SEND_LOCK; t = libnet_build_tcp( ntohs(sport), /* source port */ ntohs(dport), /* destination port */ ntohl(seq), /* sequence number */ ntohl(ack), /* acknowledgement num */ flags, /* control flags */ 32767, /* window size */ 0, /* checksum */ 0, /* urgent pointer */ LIBNET_TCP_H, /* TCP packet size */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); /* libnet id */ ON_ERROR(t, -1, "libnet_build_tcp: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); switch (proto) { case AF_INET: { /* create the IP header */ t = libnet_build_ipv4( LIBNET_IPV4_H + LIBNET_TCP_H, /* length */ 0, /* TOS */ htons(EC_MAGIC_16), /* IP ID */ 0, /* IP Frag */ 64, /* TTL */ IPPROTO_TCP, /* protocol */ 0, /* checksum */ *sip->addr32, /* source IP */ *tip->addr32, /* destination IP */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); ON_ERROR(t, -1, "libnet_build_ipv4: %s", libnet_geterror(l)); /* auto calculate the checksum */ libnet_toggle_checksum(l, t, LIBNET_ON); /* set Ethertype to IPv4 */ ethertype = ETHERTYPE_IP; break; } #ifdef WITH_IPV6 case AF_INET6: { struct libnet_in6_addr src, dst; memcpy(&src, sip->addr, sizeof(src)); memcpy(&dst, tip->addr, sizeof(dst)); t = libnet_build_ipv6( 0, /* traffic class */ 0, /* flow label */ LIBNET_TCP_H, /* payload length */ IPPROTO_TCP, /* next header */ 255, /* hop limit */ src, /* source IP */ dst, /* destination IP */ NULL, /* payload */ 0, /* payload size */ l, /* libnet handle */ 0); ON_ERROR(t, -1, "libnet_build_ipv6: %s", libnet_geterror(l)); /* set Ethertype to IPv6 */ ethertype = ETHERTYPE_IPV6; break; } #endif } /* add the media header */ t = ec_build_link_layer(EC_GBL_PCAP->dlt, dmac, ethertype, l); if (t == -1) FATAL_ERROR("Interface not suitable for layer2 sending"); /* send the packet to Layer 3 */ c = libnet_write(l); ON_ERROR(c, -1, "libnet_write (%d): %s", c, libnet_geterror(l)); /* clear the pblock */ libnet_clear_packet(l); SEND_UNLOCK; return c; } /* EOF */ // vim:ts=3:expandtab