d6_socket.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Copyright (C) 2011 Denys Vlasenko.
  4. *
  5. * Licensed under GPLv2, see file LICENSE in this source tree.
  6. */
  7. #include "common.h"
  8. #include "d6_common.h"
  9. #include <net/if.h>
  10. #include <ifaddrs.h>
  11. #include <netpacket/packet.h>
  12. int FAST_FUNC d6_read_interface(
  13. const char *interface,
  14. int *ifindex,
  15. struct in6_addr *nip6,
  16. uint8_t *mac)
  17. {
  18. int retval = 3;
  19. struct ifaddrs *ifap, *ifa;
  20. getifaddrs(&ifap);
  21. for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
  22. struct sockaddr_in6 *sip6;
  23. if (!ifa->ifa_addr || (strcmp(ifa->ifa_name, interface) != 0))
  24. continue;
  25. if (ifa->ifa_addr->sa_family == AF_PACKET) {
  26. struct sockaddr_ll *sll = (void*)(ifa->ifa_addr);
  27. memcpy(mac, sll->sll_addr, 6);
  28. log2("MAC %02x:%02x:%02x:%02x:%02x:%02x",
  29. mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
  30. );
  31. *ifindex = sll->sll_ifindex;
  32. log2("ifindex %d", *ifindex);
  33. retval &= (3 - (1<<0));
  34. }
  35. #if 0
  36. if (ifa->ifa_addr->sa_family == AF_INET) {
  37. *nip = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
  38. log1("IP %s", inet_ntoa(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr));
  39. }
  40. #endif
  41. /* RFC 3315
  42. * 16. Client Source Address and Interface Selection
  43. *
  44. * "When a client sends a DHCP message to the
  45. * All_DHCP_Relay_Agents_and_Servers address, ... ... The client
  46. * MUST use a link-local address assigned to the interface for which it
  47. * is requesting configuration information as the source address in the
  48. * header of the IP datagram."
  49. */
  50. sip6 = (void*)(ifa->ifa_addr);
  51. if (ifa->ifa_addr->sa_family == AF_INET6
  52. && IN6_IS_ADDR_LINKLOCAL(&sip6->sin6_addr)
  53. ) {
  54. *nip6 = sip6->sin6_addr; /* struct copy */
  55. log1(
  56. "IPv6 %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
  57. nip6->s6_addr[0], nip6->s6_addr[1],
  58. nip6->s6_addr[2], nip6->s6_addr[3],
  59. nip6->s6_addr[4], nip6->s6_addr[5],
  60. nip6->s6_addr[6], nip6->s6_addr[7],
  61. nip6->s6_addr[8], nip6->s6_addr[9],
  62. nip6->s6_addr[10], nip6->s6_addr[11],
  63. nip6->s6_addr[12], nip6->s6_addr[13],
  64. nip6->s6_addr[14], nip6->s6_addr[15]
  65. );
  66. retval &= (3 - (1<<1));
  67. }
  68. }
  69. freeifaddrs(ifap);
  70. if (retval & (1<<0)) {
  71. /* This iface has no MAC (e.g. ppp), generate a random one */
  72. struct ifreq ifr;
  73. int fd;
  74. /*memset(&ifr, 0, sizeof(ifr)); - SIOCGIFINDEX does not need to clear all */
  75. strncpy_IFNAMSIZ(ifr.ifr_name, interface);
  76. fd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
  77. if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
  78. *ifindex = ifr.ifr_ifindex;
  79. log2("ifindex %d", *ifindex);
  80. if (((uint32_t*)mac)[0] == 0) {
  81. /* invent a fictitious MAC (once) */
  82. ((uint32_t*)mac)[0] = rand();
  83. ((uint16_t*)mac)[2] = rand();
  84. mac[0] &= 0xfc; /* make sure it's not bcast */
  85. }
  86. retval &= (3 - (1<<0));
  87. }
  88. close(fd);
  89. }
  90. if (retval == 0)
  91. return retval;
  92. if (retval & (1<<0))
  93. bb_error_msg("can't get %s", "MAC");
  94. if (retval & (1<<1))
  95. bb_error_msg("can't get %s", "link-local IPv6 address");
  96. return retval;
  97. }
  98. int FAST_FUNC d6_listen_socket(int port, const char *inf)
  99. {
  100. int fd;
  101. struct sockaddr_in6 addr;
  102. log1("opening listen socket on *:%d %s", port, inf);
  103. fd = xsocket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
  104. setsockopt_reuseaddr(fd);
  105. if (setsockopt_broadcast(fd) == -1)
  106. bb_simple_perror_msg_and_die("SO_BROADCAST");
  107. /* NB: bug 1032 says this doesn't work on ethernet aliases (ethN:M) */
  108. if (setsockopt_bindtodevice(fd, inf))
  109. xfunc_die(); /* warning is already printed */
  110. memset(&addr, 0, sizeof(addr));
  111. addr.sin6_family = AF_INET6;
  112. addr.sin6_port = htons(port);
  113. /* addr.sin6_addr is all-zeros */
  114. xbind(fd, (struct sockaddr *)&addr, sizeof(addr));
  115. return fd;
  116. }