diff options
Diffstat (limited to 'rdns_scan/zmap4rdns/src/get_gateway-linux.h')
| -rw-r--r-- | rdns_scan/zmap4rdns/src/get_gateway-linux.h | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/rdns_scan/zmap4rdns/src/get_gateway-linux.h b/rdns_scan/zmap4rdns/src/get_gateway-linux.h new file mode 100644 index 0000000..629c571 --- /dev/null +++ b/rdns_scan/zmap4rdns/src/get_gateway-linux.h @@ -0,0 +1,311 @@ +/* + * ZMap Copyright 2013 Regents of the University of Michigan + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +#ifndef ZMAP_GET_GATEWAY_LINUX_H +#define ZMAP_GET_GATEWAY_LINUX_H + +#ifdef ZMAP_GET_GATEWAY_BSD_H +#error "Don't include both get_gateway-bsd.h and get_gateway-linux.h" +#endif + +#include <sys/ioctl.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#include <arpa/inet.h> +#include <pcap/pcap.h> + +#define GW_BUFFER_SIZE 64000 + +char *get_default_iface(void) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + char *iface = pcap_lookupdev(errbuf); + if (iface == NULL) { + log_fatal("send", "ZMap could not detect your default network interface. " + "You likely do not privileges to open a raw packet socket. " + "Are you running as root or with the CAP_NET_RAW capability? If you are, you " + "may need to manually set interface using the \"-i\" flag."); + } + return iface; +} + +int read_nl_sock(int sock, char *buf, int buf_len) +{ + int msg_len = 0; + char *pbuf = buf; + do { + int len = recv(sock, pbuf, buf_len - msg_len, 0); + if (len <= 0) { + log_debug("get-gw", "recv failed: %s", strerror(errno)); + return -1; + } + struct nlmsghdr *nlhdr = (struct nlmsghdr *)pbuf; + if (NLMSG_OK(nlhdr, ((unsigned int)len)) == 0 || + nlhdr->nlmsg_type == NLMSG_ERROR) { + log_debug("get-gw", "recv failed: %s", strerror(errno)); + return -1; + } + if (nlhdr->nlmsg_type == NLMSG_DONE) { + break; + } else { + msg_len += len; + pbuf += len; + } + if ((nlhdr->nlmsg_flags & NLM_F_MULTI) == 0) { + break; + } + } while (1); + return msg_len; +} + +int send_nl_req(uint16_t msg_type, uint32_t seq, void *payload, + uint32_t payload_len) +{ + int sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + if (sock < 0) { + log_error("get-gw", "unable to get socket: %s", + strerror(errno)); + return -1; + } + if (NLMSG_SPACE(payload_len) < payload_len) { + close(sock); + // Integer overflow + return -1; + } + struct nlmsghdr *nlmsg; + nlmsg = xmalloc(NLMSG_SPACE(payload_len)); + + memset(nlmsg, 0, NLMSG_SPACE(payload_len)); + memcpy(NLMSG_DATA(nlmsg), payload, payload_len); + nlmsg->nlmsg_type = msg_type; + nlmsg->nlmsg_len = NLMSG_LENGTH(payload_len); + nlmsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; + nlmsg->nlmsg_seq = seq; + nlmsg->nlmsg_pid = getpid(); + + if (send(sock, nlmsg, nlmsg->nlmsg_len, 0) < 0) { + log_error("get-gw", "failure sending: %s", strerror(errno)); + return -1; + } + free(nlmsg); + return sock; +} + +int get_hw_addr(struct in_addr *gw_ip, char *iface, unsigned char *hw_mac) +{ + struct ndmsg req; + memset(&req, 0, sizeof(struct ndmsg)); + + if (!gw_ip || !hw_mac) { + return -1; + } + // Send RTM_GETNEIGH request + req.ndm_family = AF_INET; + req.ndm_ifindex = if_nametoindex(iface); + req.ndm_state = NUD_REACHABLE; + req.ndm_type = NDA_LLADDR; + + int sock = send_nl_req(RTM_GETNEIGH, 1, &req, sizeof(req)); + // Read responses + char *buf = xmalloc(GW_BUFFER_SIZE); + int nl_len = read_nl_sock(sock, buf, GW_BUFFER_SIZE); + if (nl_len <= 0) { + free(buf); + return -1; + } + // Parse responses + struct nlmsghdr *nlhdr = (struct nlmsghdr *)buf; + while (NLMSG_OK(nlhdr, nl_len)) { + struct rtattr *rt_attr; + struct rtmsg *rt_msg; + int rt_len; + unsigned char mac[6]; + struct in_addr dst_ip; + int correct_ip = 0; + + rt_msg = (struct rtmsg *)NLMSG_DATA(nlhdr); + if ((rt_msg->rtm_family != AF_INET)) { + free(buf); + return -1; + } + rt_attr = (struct rtattr *)RTM_RTA(rt_msg); + rt_len = RTM_PAYLOAD(nlhdr); + while (RTA_OK(rt_attr, rt_len)) { + switch (rt_attr->rta_type) { + case NDA_LLADDR: + if (RTA_PAYLOAD(rt_attr) != IFHWADDRLEN) { + // could be using a VPN + log_fatal( + "get_gateway", + "Unexpected hardware address length (%d)." + " If you are using a VPN, supply the --iplayer flag (and provide an" + " interface via -i)", + RTA_PAYLOAD(rt_attr)); + } + memcpy(mac, RTA_DATA(rt_attr), IFHWADDRLEN); + break; + case NDA_DST: + if (RTA_PAYLOAD(rt_attr) != sizeof(dst_ip)) { + // could be using a VPN + log_fatal( + "get_gateway", + "Unexpected IP address length (%d)." + " If you are using a VPN, supply the --iplayer flag" + " (and provide an interface via -i)", + RTA_PAYLOAD(rt_attr)); + } + memcpy(&dst_ip, RTA_DATA(rt_attr), + sizeof(dst_ip)); + if (memcmp(&dst_ip, gw_ip, sizeof(dst_ip)) == + 0) { + correct_ip = 1; + } + break; + } + rt_attr = RTA_NEXT(rt_attr, rt_len); + } + if (correct_ip) { + memcpy(hw_mac, mac, IFHWADDRLEN); + free(buf); + return 0; + } + nlhdr = NLMSG_NEXT(nlhdr, nl_len); + } + free(buf); + return -1; +} + +// gw and iface[IF_NAMESIZE] MUST be allocated +int _get_default_gw(struct in_addr *gw, char *iface) +{ + struct rtmsg req; + unsigned int nl_len; + char buf[8192]; + struct nlmsghdr *nlhdr; + + if (!gw || !iface) { + return -1; + } + + // Send RTM_GETROUTE request + memset(&req, 0, sizeof(req)); + int sock = send_nl_req(RTM_GETROUTE, 0, &req, sizeof(req)); + + // Read responses + nl_len = read_nl_sock(sock, buf, sizeof(buf)); + if (nl_len <= 0) { + return -1; + } + + // Parse responses + nlhdr = (struct nlmsghdr *)buf; + while (NLMSG_OK(nlhdr, nl_len)) { + struct rtattr *rt_attr; + struct rtmsg *rt_msg; + int rt_len; + int has_gw = 0; + + rt_msg = (struct rtmsg *)NLMSG_DATA(nlhdr); + + // There could be multiple routing tables. Loop until we find the + // correct one. + if ((rt_msg->rtm_family != AF_INET) || + (rt_msg->rtm_table != RT_TABLE_MAIN)) { + nlhdr = NLMSG_NEXT(nlhdr, nl_len); + continue; + } + + rt_attr = (struct rtattr *)RTM_RTA(rt_msg); + rt_len = RTM_PAYLOAD(nlhdr); + while (RTA_OK(rt_attr, rt_len)) { + switch (rt_attr->rta_type) { + case RTA_OIF: + if_indextoname(*(int *)RTA_DATA(rt_attr), + iface); + break; + case RTA_GATEWAY: + gw->s_addr = *(unsigned int *)RTA_DATA(rt_attr); + has_gw = 1; + break; + } + rt_attr = RTA_NEXT(rt_attr, rt_len); + } + + if (has_gw) { + return 0; + } + nlhdr = NLMSG_NEXT(nlhdr, nl_len); + } + return -1; +} + +int get_default_gw(struct in_addr *gw, char *iface) +{ + char _iface[IF_NAMESIZE]; + memset(_iface, 0, IF_NAMESIZE); + + _get_default_gw(gw, _iface); + if (strcmp(iface, _iface)) { + log_fatal( + "get-gateway", + "The specified network (\"%s\") does not match " + "the interface associated with the default gateway (%s). You will " + "need to manually specify the MAC address of your gateway using " + "the \"--gateway-mac\" flag.", iface, _iface); + } + return EXIT_SUCCESS; +} + +int get_iface_ip(char *iface, struct in_addr *ip) +{ + int sock; + struct ifreq ifr; + memset(&ifr, 0, sizeof(struct ifreq)); + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + log_fatal("get-iface-ip", "failure opening socket: %s", + strerror(errno)); + } + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1); + + if (ioctl(sock, SIOCGIFADDR, &ifr) < 0) { + close(sock); + log_fatal("get-iface-ip", "Unable to automatically identify the correct " + "source address for %s interface. ioctl failure: %s. " + "If this is the unexpected interface, you can manually specify " + "the correct interface with \"-i\" flag. If this is the correct " + "interface, you likely need to manually specify the source IP " + "address to use with the \"-S\" flag.", iface, strerror(errno)); + } + ip->s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; + close(sock); + return EXIT_SUCCESS; +} + +int get_iface_hw_addr(char *iface, unsigned char *hw_mac) +{ + int s; + struct ifreq buffer; + + // Load the hwaddr from a dummy socket + s = socket(PF_INET, SOCK_DGRAM, 0); + if (s < 0) { + log_error("get_iface_hw_addr", "Unable to open socket: %s", + strerror(errno)); + return EXIT_FAILURE; + } + memset(&buffer, 0, sizeof(buffer)); + strncpy(buffer.ifr_name, iface, IFNAMSIZ); + ioctl(s, SIOCGIFHWADDR, &buffer); + close(s); + memcpy(hw_mac, buffer.ifr_hwaddr.sa_data, 6); + return EXIT_SUCCESS; +} + +#endif /* ZMAP_GET_GATEWAY_LINUX_H */ |
