diff --git a/configure.ac b/configure.ac index e100490..11e550b 100644 --- a/configure.ac +++ b/configure.ac @@ -9,6 +9,46 @@ AC_SUBST(VERSION) AC_PROG_INSTALL AC_PROG_CC +AC_CANONICAL_HOST + +case "$host" in +*-*-linux*) + AC_DEFINE([LLADDR(s)], [s->sll_addr], [the link level address]) +;; +*-*-freebsd*) + AC_DEFINE([sockaddr_ll], [sockaddr_dl], [the socket link structures]) + AC_DEFINE([sll_family], [sdl_family], [the socket family member]) + AC_DEFINE([AF_PACKET], [AF_LINK], [the domain name]) + AC_DEFINE([ifr_hwaddr], [ifr_addr], [the address member]) + AC_DEFINE([SIOCSIFHWADDR], [SIOCSIFLLADDR], [the ioctl call]) +;; +esac + +AC_MSG_CHECKING([if sockaddr has the sa_len member]) +AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ #include ]], + [[ struct sockaddr sock; return (sock.sa_len); ]])], + [AC_DEFINE([HAVE_SOCKADDR_SA_LEN], [1], + [socket address structures have length fields]) +]) + +AC_CHECK_HEADER([ifaddrs.h], ,[AC_MSG_ERROR( + [*** ifaddrs.h missing - please install first or check config.log ***])]) + +AC_CHECK_HEADERS([linux/if_packet.h net/if_dl.h]) + +if test "x$ac_cv_header_linux_if_packet_h" = "xyes" ; then + AC_DEFINE([HAVE_IF_PACKET], [1], + [The Linux if_packet.h header found]) +elif test "x$ac_cv_header_net_if_dl_h" = "xyes" ; then + AC_DEFINE([HAVE_IF_DL], [1], + [The BSD if_dl.h header found]) +else + AC_MSG_ERROR([*** sockaddr_* missing - please install first or check config.log ***]) +fi + +AC_CHECK_HEADER(linux/ethtool.h, AC_DEFINE([HAVE_ETHTOOL], [1], [Linux ethernet headers found]), ) AC_OUTPUT([ Makefile diff --git a/src/main.c b/src/main.c index 711ffe7..4f5ad93 100644 --- a/src/main.c +++ b/src/main.c @@ -40,9 +40,6 @@ #include "maclist.h" #include "netinfo.h" -#define EXIT_OK 0 -#define EXIT_ERROR 1 - static void print_help (void) { @@ -54,7 +51,9 @@ print_help (void) " -e, --ending Don't change the vendor bytes\n" " -a, --another Set random vendor MAC of the same kind\n" " -A Set random vendor MAC of any kind\n" +#if defined(HAVE_ETHTOOL) " -p, --permanent Reset to original, permanent hardware MAC\n" +#endif " -r, --random Set fully random MAC\n" " -l, --list[=keyword] Print known vendors\n" " -b, --bia Pretend to be a burned-in-address\n" @@ -116,7 +115,9 @@ main (int argc, char *argv[]) char ending = 0; char another_any = 0; char another_same = 0; +#if defined(HAVE_ETHTOOL) char permanent = 0; +#endif char print_list = 0; char show = 0; char set_bia = 0; @@ -131,7 +132,9 @@ main (int argc, char *argv[]) {"ending", no_argument, NULL, 'e'}, {"endding", no_argument, NULL, 'e'}, /* kept for backwards compatibility */ {"another", no_argument, NULL, 'a'}, +#if defined(HAVE_ETHTOOL) {"permanent", no_argument, NULL, 'p'}, +#endif {"show", no_argument, NULL, 's'}, {"another_any", no_argument, NULL, 'A'}, {"bia", no_argument, NULL, 'b'}, @@ -142,7 +145,9 @@ main (int argc, char *argv[]) net_info_t *net; mac_t *mac; +#if defined(HAVE_ETHTOOL) mac_t *mac_permanent; +#endif mac_t *mac_faked; char *device_name; int val; @@ -158,7 +163,7 @@ main (int argc, char *argv[]) "This is free software; see the source for copying conditions. There is NO\n" "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", VERSION); - exit (EXIT_OK); + exit (EXIT_SUCCESS); break; case 'l': print_list = 1; @@ -182,9 +187,11 @@ main (int argc, char *argv[]) case 'A': another_any = 1; break; +#if defined(HAVE_ETHTOOL) case 'p': permanent = 1; break; +#endif case 'm': set_mac = optarg; break; @@ -192,26 +199,26 @@ main (int argc, char *argv[]) case '?': default: print_help(); - exit (EXIT_OK); + exit (EXIT_SUCCESS); break; } } /* Read the MAC lists */ if (mc_maclist_init() < 0) { - exit (EXIT_ERROR); + exit (EXIT_FAILURE); } /* Print list? */ if (print_list) { mc_maclist_print(search_word); - exit (EXIT_OK); + exit (EXIT_SUCCESS); } /* Get device name argument */ if (optind >= argc) { print_usage(); - exit (EXIT_OK); + exit (EXIT_SUCCESS); } device_name = argv[optind]; @@ -220,10 +227,12 @@ main (int argc, char *argv[]) /* Read the MAC */ if ((net = mc_net_info_new(device_name)) == NULL) { - exit (EXIT_ERROR); + exit (EXIT_FAILURE); } mac = mc_net_info_get_mac(net); +#if defined(HAVE_ETHTOOL) mac_permanent = mc_net_info_get_permanent_mac(net); +#endif /* --bia can only be used with --random */ if (set_bia && !random) { @@ -232,16 +241,18 @@ main (int argc, char *argv[]) /* Print the current MAC info */ print_mac ("Current MAC: ", mac); +#if defined(HAVE_ETHTOOL) print_mac ("Permanent MAC: ", mac_permanent); +#endif /* Change the MAC */ mac_faked = mc_mac_dup (mac); if (show) { - exit (EXIT_OK); + exit (EXIT_SUCCESS); } else if (set_mac) { if (mc_mac_read_string (mac_faked, set_mac) < 0) { - exit (EXIT_ERROR); + exit (EXIT_FAILURE); } } else if (random) { mc_mac_random (mac_faked, 6, set_bia); @@ -254,10 +265,12 @@ main (int argc, char *argv[]) } else if (another_any) { mc_maclist_set_random_vendor(mac_faked, mac_is_anykind); mc_mac_random (mac_faked, 3, 1); +#if defined(HAVE_ETHTOOL) } else if (permanent) { mac_faked = mc_mac_dup (mac_permanent); +#endif } else { - exit (EXIT_OK); /* default to show */ + exit (EXIT_SUCCESS); /* default to show */ } /* Set the new MAC */ @@ -279,9 +292,11 @@ main (int argc, char *argv[]) /* Memory free */ mc_mac_free (mac); mc_mac_free (mac_faked); +#if defined(HAVE_ETHTOOL) mc_mac_free (mac_permanent); +#endif mc_net_info_free (net); mc_maclist_free(); - return (ret == 0) ? EXIT_OK : EXIT_ERROR; + return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/netinfo.c b/src/netinfo.c index 3525123..25d8182 100644 --- a/src/netinfo.c +++ b/src/netinfo.c @@ -23,14 +23,30 @@ * USA */ +#ifdef HAVE_CONFIG_H +# include +#endif + #include #include #include #include #include -#include -#include +#include +#include +#include + +#if defined(HAVE_IF_PACKET) +# include +#elif defined(HAVE_IF_DL) +# include +#endif + +#if defined(HAVE_ETHTOOL) +# include +# include +#endif #include "netinfo.h" @@ -49,7 +65,7 @@ mc_net_info_new (const char *device) strncpy (new->dev.ifr_name, device, sizeof(new->dev.ifr_name)); new->dev.ifr_name[sizeof(new->dev.ifr_name)-1] = '\0'; - if (ioctl(new->sock, SIOCGIFHWADDR, &new->dev) < 0) { + if (if_nametoindex(device) == 0) { perror ("[ERROR] Set device name"); free(new); return NULL; @@ -66,29 +82,55 @@ mc_net_info_free (net_info_t *net) free(net); } - mac_t * mc_net_info_get_mac (const net_info_t *net) { - int i; - mac_t *new = (mac_t *) malloc (sizeof(mac_t)); + int i; + mac_t *mac = (mac_t *) malloc (sizeof(mac_t)); + u_char *lladr; - for (i=0; i<6; i++) { - new->byte[i] = net->dev.ifr_hwaddr.sa_data[i] & 0xFF; - } + struct ifaddrs *ifap, *ifa; + struct sockaddr_ll *sdl; - return new; -} + if (getifaddrs(&ifap) == 0) { + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + + sdl = (struct sockaddr_ll *) ifa->ifa_addr; + if (strcmp(ifa->ifa_name, net->dev.ifr_name) != 0) + continue; + + if (!sdl && sdl->sll_family != AF_PACKET) + continue; + + lladr = (u_char *) LLADDR(sdl); + for (i=0; i<6; i++) + mac->byte[i] = lladr[i] & 0xFF; + break; + } + freeifaddrs(ifap); + } else + perror("getifaddrs"); + + return mac; +} int mc_net_info_set_mac (net_info_t *net, const mac_t *mac) { int i; +#if defined(HAVE_ETHTOOL) + if (ioctl(net->sock, SIOCGIFHWADDR, &net->dev) < 0) { + perror ("[ERROR] Set ifreq structure"); + return -1; + } +#elif defined(HAVE_SOCKADDR_SA_LEN) + net->dev.ifr_addr.sa_family = AF_PACKET; + net->dev.ifr_addr.sa_len = ETHER_ADDR_LEN; +#endif - for (i=0; i<6; i++) { + for (i=0; i<6; i++) net->dev.ifr_hwaddr.sa_data[i] = mac->byte[i]; - } if (ioctl(net->sock, SIOCSIFHWADDR, &net->dev) < 0) { perror ("[ERROR] Could not change MAC: interface up or insufficient permissions"); @@ -98,6 +140,7 @@ mc_net_info_set_mac (net_info_t *net, const mac_t *mac) return 0; } +#if defined(HAVE_ETHTOOL) mac_t * mc_net_info_get_permanent_mac (const net_info_t *net) { @@ -126,3 +169,4 @@ mc_net_info_get_permanent_mac (const net_info_t *net) free(epa); return newmac; } +#endif