123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- /*
- * 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>
- char *get_default_iface(void)
- {
- char errbuf[PCAP_ERRBUF_SIZE];
- char *iface = pcap_lookupdev(errbuf);
- if (iface == NULL) {
- log_fatal("zmap", "could not detect default network interface "
- "(e.g. eth0). Try running as root or setting"
- " interface using -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)
- {
- char buf[8192];
- memset(&buf, 0, 8192);
- struct ndmsg req;
- memset(&req, 0, sizeof(struct ndmsg));
- struct nlmsghdr *nlhdr;
- 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
- unsigned 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;
- 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)) {
- 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).\n\n"
- " If you are using a VPN, supply the --vpn flag (and provide an"
- " interface via -i)",
- RTA_PAYLOAD(rt_attr));
- exit(1);
- }
- 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).\n"
- " If you are using a VPN, supply the --vpn flag"
- " (and provide an interface via -i)",
- RTA_PAYLOAD(rt_attr));
- exit(1);
- }
- 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);
- return 0;
- }
- nlhdr = NLMSG_NEXT(nlhdr, nl_len);
- }
- 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);
- if ((rt_msg->rtm_family != AF_INET) || (rt_msg->rtm_table != RT_TABLE_MAIN)) {
- 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 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) != 0) {
- log_fatal("get-gateway", "interface specified (%s) does not match "
- "the interface of the default gateway (%s). You will need "
- "to manually specify the MAC address of your gateway.",
- 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", "ioctl failure: %s", 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 */
|