nameif.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * nameif.c - Naming Interfaces based on MAC address for busybox.
  3. *
  4. * Written 2000 by Andi Kleen.
  5. * Busybox port 2002 by Nick Fedchik <nick@fedchik.org.ua>
  6. * Glenn McGrath <bug1@iinet.net.au>
  7. *
  8. * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
  9. */
  10. #include <sys/syslog.h>
  11. #include <sys/socket.h>
  12. #include <sys/ioctl.h>
  13. #include <errno.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <unistd.h>
  17. #include <net/if.h>
  18. #include <netinet/ether.h>
  19. #include "busybox.h"
  20. /* Older versions of net/if.h do not appear to define IF_NAMESIZE. */
  21. #ifndef IF_NAMESIZE
  22. # ifdef IFNAMSIZ
  23. # define IF_NAMESIZE IFNAMSIZ
  24. # else
  25. # define IF_NAMESIZE 16
  26. # endif
  27. #endif
  28. /* take from linux/sockios.h */
  29. #define SIOCSIFNAME 0x8923 /* set interface name */
  30. /* Octets in one Ethernet addr, from <linux/if_ether.h> */
  31. #define ETH_ALEN 6
  32. #ifndef ifr_newname
  33. #define ifr_newname ifr_ifru.ifru_slave
  34. #endif
  35. typedef struct mactable_s {
  36. struct mactable_s *next;
  37. struct mactable_s *prev;
  38. char *ifname;
  39. struct ether_addr *mac;
  40. } mactable_t;
  41. static unsigned long flags;
  42. static void serror(const char *s, ...) ATTRIBUTE_NORETURN;
  43. static void serror(const char *s, ...)
  44. {
  45. va_list ap;
  46. va_start(ap, s);
  47. if (flags & 1) {
  48. openlog(bb_applet_name, 0, LOG_LOCAL0);
  49. vsyslog(LOG_ERR, s, ap);
  50. closelog();
  51. } else {
  52. bb_verror_msg(s, ap);
  53. putc('\n', stderr);
  54. }
  55. va_end(ap);
  56. exit(EXIT_FAILURE);
  57. }
  58. /* Check ascii str_macaddr, convert and copy to *mac */
  59. static struct ether_addr *cc_macaddr(const char *str_macaddr)
  60. {
  61. struct ether_addr *lmac, *mac;
  62. lmac = ether_aton(str_macaddr);
  63. if (lmac == NULL)
  64. serror("cannot parse MAC %s", str_macaddr);
  65. mac = xmalloc(ETH_ALEN);
  66. memcpy(mac, lmac, ETH_ALEN);
  67. return mac;
  68. }
  69. int nameif_main(int argc, char **argv)
  70. {
  71. mactable_t *clist = NULL;
  72. FILE *ifh;
  73. const char *fname = "/etc/mactab";
  74. char *line;
  75. int ctl_sk;
  76. int if_index = 1;
  77. mactable_t *ch;
  78. flags = bb_getopt_ulflags(argc, argv, "sc:", &fname);
  79. if ((argc - optind) & 1)
  80. bb_show_usage();
  81. if (optind < argc) {
  82. char **a = argv + optind;
  83. while (*a) {
  84. if (strlen(*a) > IF_NAMESIZE)
  85. serror("interface name `%s' too long", *a);
  86. ch = xcalloc(1, sizeof(mactable_t));
  87. ch->ifname = bb_xstrdup(*a++);
  88. ch->mac = cc_macaddr(*a++);
  89. if (clist)
  90. clist->prev = ch;
  91. ch->next = clist;
  92. clist = ch;
  93. }
  94. } else {
  95. ifh = bb_xfopen(fname, "r");
  96. while ((line = bb_get_line_from_file(ifh)) != NULL) {
  97. char *line_ptr;
  98. size_t name_length;
  99. line_ptr = line + strspn(line, " \t");
  100. if ((line_ptr[0] == '#') || (line_ptr[0] == '\n')) {
  101. free(line);
  102. continue;
  103. }
  104. name_length = strcspn(line_ptr, " \t");
  105. ch = xcalloc(1, sizeof(mactable_t));
  106. ch->ifname = bb_xstrndup(line_ptr, name_length);
  107. if (name_length > IF_NAMESIZE)
  108. serror("interface name `%s' too long", ch->ifname);
  109. line_ptr += name_length;
  110. line_ptr += strspn(line_ptr, " \t");
  111. name_length = strspn(line_ptr, "0123456789ABCDEFabcdef:");
  112. line_ptr[name_length] = '\0';
  113. ch->mac = cc_macaddr(line_ptr);
  114. if (clist)
  115. clist->prev = ch;
  116. ch->next = clist;
  117. clist = ch;
  118. free(line);
  119. }
  120. fclose(ifh);
  121. }
  122. if ((ctl_sk = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
  123. serror("socket: %m");
  124. while (clist) {
  125. struct ifreq ifr;
  126. memset(&ifr, 0, sizeof(struct ifreq));
  127. if_index++;
  128. ifr.ifr_ifindex = if_index;
  129. /* Get ifname by index or die */
  130. if (ioctl(ctl_sk, SIOCGIFNAME, &ifr))
  131. break;
  132. /* Has this device hwaddr? */
  133. if (ioctl(ctl_sk, SIOCGIFHWADDR, &ifr))
  134. continue;
  135. /* Search for mac like in ifr.ifr_hwaddr.sa_data */
  136. for (ch = clist; ch; ch = ch->next)
  137. if (!memcmp(ch->mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN))
  138. break;
  139. /* Nothing found for current ifr.ifr_hwaddr.sa_data */
  140. if (ch == NULL)
  141. continue;
  142. strcpy(ifr.ifr_newname, ch->ifname);
  143. if (ioctl(ctl_sk, SIOCSIFNAME, &ifr) < 0)
  144. serror("cannot change ifname %s to %s: %m",
  145. ifr.ifr_name, ch->ifname);
  146. /* Remove list entry of renamed interface */
  147. if (ch->prev != NULL) {
  148. (ch->prev)->next = ch->next;
  149. } else {
  150. clist = ch->next;
  151. }
  152. if (ch->next != NULL)
  153. (ch->next)->prev = ch->prev;
  154. #ifdef CONFIG_FEATURE_CLEAN_UP
  155. free(ch->ifname);
  156. free(ch->mac);
  157. free(ch);
  158. #endif
  159. }
  160. return 0;
  161. }